Skip to content

Commit f716a6a

Browse files
committed
refactoring to demonstrate services and node composition
1 parent aec1cdb commit f716a6a

File tree

11 files changed

+213
-31
lines changed

11 files changed

+213
-31
lines changed

.clang-format

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Language: Cpp
2+
BasedOnStyle: Google
3+
4+
AccessModifierOffset: -2
5+
AlignAfterOpenBracket: AlwaysBreak
6+
BraceWrapping:
7+
AfterClass: true
8+
AfterFunction: true
9+
AfterNamespace: true
10+
AfterStruct: true
11+
AfterEnum: true
12+
BreakBeforeBraces: Custom
13+
ColumnLimit: 100
14+
ConstructorInitializerIndentWidth: 0
15+
ContinuationIndentWidth: 2
16+
DerivePointerAlignment: false
17+
PointerAlignment: Middle
18+
ReflowComments: false
19+

README.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1-
# ZigROS rclcpp examples
1+
# ZigROS rclcpp example
2+
3+
This repo contains an example C++ node built with zig and ZigROS.
4+
It showcases the suggested single executable use case for ZigROS by writing nodes as libraries and composing them by hand into a single executable.
5+
6+
Checkout the ZigROS repo for a more in depth intro to the ZigROS library.
7+
8+
## How to build
9+
10+
The only dependency this repo has is on the zig compiler.
11+
Make sure you have zig 0.13 available on your system, then simply build with:
12+
13+
```
14+
zig build -Doptimize=ReleaseFast -Dtarget=x86_64-linux-musl
15+
```
16+
17+
Then run with
18+
19+
```
20+
./zig-out/bin/node
21+
```
22+
23+
The build.zig file shows some suggested build tricks, such as stripping the binary if not in debug mode, and setting the section flags if building with the release small flag.
224

3-
This repo contains an example C++ node built with zig and zigros.

build.zig

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ pub fn build(b: *std.Build) void {
1919
});
2020

2121
pub_sub_node.want_lto = true;
22-
pub_sub_node.link_function_sections = true;
23-
pub_sub_node.link_data_sections = true;
24-
pub_sub_node.link_gc_sections = true;
22+
23+
// The core ZigROS libraries will also set these flags if ReleaseSmall is used.
24+
if (optimize == .ReleaseSmall) {
25+
pub_sub_node.link_function_sections = true;
26+
pub_sub_node.link_data_sections = true;
27+
pub_sub_node.link_gc_sections = true;
28+
}
2529

2630
const zigros = ZigRos.init(b.dependency("zigros", .{
2731
.target = target,
@@ -35,9 +39,15 @@ pub fn build(b: *std.Build) void {
3539
zigros.linkRmwCycloneDds(&pub_sub_node.root_module);
3640
zigros.linkLoggerSpd(&pub_sub_node.root_module);
3741

42+
pub_sub_node.addIncludePath(b.path("include"));
3843
pub_sub_node.addCSourceFiles(.{
3944
.root = b.path("src"),
40-
.files = &.{"main.cpp"},
45+
.files = &.{
46+
"main.cpp",
47+
"subscription.cpp",
48+
"publisher.cpp",
49+
"service.cpp",
50+
},
4151
.flags = &.{
4252
"--std=c++17",
4353
"-Wno-deprecated-declarations",
@@ -49,11 +59,15 @@ pub fn build(b: *std.Build) void {
4959
"zigros_example_interface",
5060
.{ .target = target, .optimize = optimize, .linkage = linkage },
5161
);
52-
interface.addInterfaces(b.path(""), &.{"msg/Example.msg"});
62+
interface.addInterfaces(b.path(""), &.{
63+
"msg/Example.msg",
64+
"srv/Example.srv",
65+
});
5366

5467
// the example message uses the standard header message, so we must add builtin_interfaces
5568
// as a dependency
5669
interface.addDependency("builtin_interfaces", zigros.ros_libraries.builtin_interfaces);
70+
interface.addDependency("service_msgs", zigros.ros_libraries.service_msgs);
5771
interface.artifacts.linkCpp(&pub_sub_node.root_module);
5872

5973
b.installArtifact(pub_sub_node);

include/zigros_examples/publisher.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef ZIGROS_EXAMPLES_PUBLISHER_HPP
2+
#define ZIGROS_EXAMPLES_PUBLISHER_HPP
3+
4+
#include "rclcpp/rclcpp.hpp"
5+
#include "zigros_example_interface/msg/example.hpp"
6+
7+
namespace zigros_examples
8+
{
9+
10+
class Publisher
11+
{
12+
public:
13+
Publisher(rclcpp::NodeOptions options = rclcpp::NodeOptions());
14+
15+
rclcpp::Node node_;
16+
std::shared_ptr<rclcpp::Publisher<zigros_example_interface::msg::Example>> publisher_;
17+
std::shared_ptr<rclcpp::TimerBase> timer_;
18+
};
19+
} // namespace zigros_examples
20+
#endif // ZIGROS_EXAMPLES_PUBLISHER_HPP

include/zigros_examples/service.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef ZIGROS_EXAMPLES_SERVICE_HPP
2+
#define ZIGROS_EXAMPLES_SERVICE_HPP
3+
4+
#include "rclcpp/rclcpp.hpp"
5+
#include "zigros_example_interface/srv/example.hpp"
6+
7+
namespace zigros_examples
8+
{
9+
10+
class Service
11+
{
12+
public:
13+
Service(rclcpp::NodeOptions options = rclcpp::NodeOptions());
14+
rclcpp::Node node_;
15+
std::shared_ptr<rclcpp::Service<zigros_example_interface::srv::Example>> server_;
16+
};
17+
} // namespace zigros_examples
18+
#endif // ZIGROS_EXAMPLES_SERVICE_HPP
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef ZIGROS_EXAMPLES_SUBSCRIPTION_HPP
2+
#define ZIGROS_EXAMPLES_SUBSCRIPTION_HPP
3+
4+
#include "rclcpp/rclcpp.hpp"
5+
#include "zigros_example_interface/msg/example.hpp"
6+
#include "zigros_example_interface/srv/example.hpp"
7+
8+
namespace zigros_examples
9+
{
10+
11+
class Subscription
12+
{
13+
public:
14+
Subscription(rclcpp::NodeOptions options = rclcpp::NodeOptions());
15+
rclcpp::Node node_;
16+
std::shared_ptr<rclcpp::Subscription<zigros_example_interface::msg::Example>> subscription_;
17+
std::shared_ptr<rclcpp::Client<zigros_example_interface::srv::Example>> client_;
18+
std::shared_ptr<const zigros_example_interface::msg::Example> prev_msg_;
19+
};
20+
} // namespace zigros_examples
21+
#endif // ZIGROS_EXAMPLES_SUBSCRIPTION_HPP

src/main.cpp

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
1-
#include "rclcpp/rclcpp.hpp"
2-
#include "zigros_example_interface/msg/example.hpp"
3-
#include <iostream>
1+
#include "zigros_examples/publisher.hpp"
2+
#include "zigros_examples/service.hpp"
3+
#include "zigros_examples/subscription.hpp"
44

5-
int main(int argc, char *argv[]) {
5+
int main(int argc, char * argv[])
6+
{
67
rclcpp::init(argc, argv);
7-
const auto node = std::make_shared<rclcpp::Node>("example_node", rclcpp::NodeOptions().use_intra_process_comms(true));
8-
const auto publisher = rclcpp::create_publisher<zigros_example_interface::msg::Example>(node, "test", 1);
9-
const auto subscription = rclcpp::create_subscription<zigros_example_interface::msg::Example>(
10-
node,
11-
"test",
12-
1,
13-
[node](zigros_example_interface::msg::Example::ConstSharedPtr msg) {
14-
RCLCPP_INFO_STREAM(node->get_logger(), "Time: " << msg->time.sec);
15-
});
168

17-
const auto timer = rclcpp::create_timer(
18-
node,
19-
node->get_clock(),
20-
rclcpp::Duration::from_seconds(1.0),
21-
[publisher, node](){
22-
auto msg = zigros_example_interface::msg::Example();
23-
msg.time = node->now();
24-
publisher->publish(msg);
25-
}
26-
);
9+
auto node_options = rclcpp::NodeOptions().use_intra_process_comms(true);
2710

11+
// instantiate your applicatin nodes.
12+
// this replaces your launch file.
13+
// all normal launch arguments can be passed using the node options
14+
auto publisher = zigros_examples::Publisher(node_options);
15+
auto subscription = zigros_examples::Subscription(node_options);
16+
auto service = zigros_examples::Service(node_options);
17+
18+
// For simplicity all nodes are added to the same executor.
19+
// In a more complex example where parallel execution is required, each node would typically get its own executor and be spun in its own thread.
20+
// your exact threading structure will depend on your application.
21+
// Fewer executors/threads will have less overhead, but potentially increae latency.
22+
// If callbacks depend on each other, they need to be in separate executors.
2823
auto executor = rclcpp::experimental::executors::EventsExecutor();
29-
executor.add_node(node);
24+
executor.add_node(publisher.node_.get_node_base_interface());
25+
executor.add_node(subscription.node_.get_node_base_interface());
26+
executor.add_node(service.node_.get_node_base_interface());
3027
executor.spin();
3128

3229
rclcpp::shutdown();

src/publisher.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include "zigros_examples/publisher.hpp"
2+
3+
#include "rclcpp/rclcpp.hpp"
4+
#include "zigros_example_interface/msg/example.hpp"
5+
6+
namespace zigros_examples
7+
{
8+
9+
Publisher::Publisher(rclcpp::NodeOptions options)
10+
: node_{"publisher", options},
11+
publisher_{node_.create_publisher<zigros_example_interface::msg::Example>("test", 1)},
12+
timer_{
13+
rclcpp::create_timer(&node_, node_.get_clock(), rclcpp::Duration::from_seconds(1.0), [this]() {
14+
auto msg = zigros_example_interface::msg::Example();
15+
msg.time = node_.now();
16+
publisher_->publish(msg);
17+
})}
18+
{
19+
}
20+
} // namespace zigros_examples

src/service.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include "zigros_examples/service.hpp"
2+
3+
namespace zigros_examples
4+
{
5+
6+
Service::Service(rclcpp::NodeOptions options)
7+
: node_{"service", options},
8+
server_{node_.create_service<zigros_example_interface::srv::Example>(
9+
"example", [this](
10+
zigros_example_interface::srv::Example::Request::ConstSharedPtr request,
11+
zigros_example_interface::srv::Example::Response::SharedPtr response) {
12+
response->diff = rclcpp::Time(request->a) - rclcpp::Time(request->b);
13+
})}
14+
{
15+
}
16+
} // namespace zigros_examples

src/subscription.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "zigros_examples/subscription.hpp"
2+
3+
namespace zigros_examples
4+
{
5+
6+
Subscription::Subscription(rclcpp::NodeOptions options)
7+
: node_{"subscription", options},
8+
subscription_{node_.create_subscription<zigros_example_interface::msg::Example>(
9+
"test", 1,
10+
[this](zigros_example_interface::msg::Example::ConstSharedPtr msg) {
11+
RCLCPP_INFO_STREAM(node_.get_logger(), "Time: " << msg->time.sec);
12+
if (prev_msg_) {
13+
auto request = std::make_shared<zigros_example_interface::srv::Example::Request>();
14+
request->a = msg->time;
15+
request->b = prev_msg_->time;
16+
client_->async_send_request(
17+
request,
18+
[this](rclcpp::Client<zigros_example_interface::srv::Example>::SharedFuture future) {
19+
if (future.valid()) {
20+
auto result = future.get();
21+
RCLCPP_INFO_STREAM(
22+
node_.get_logger(),
23+
"Service responce: " << rclcpp::Duration(result->diff).seconds());
24+
}
25+
});
26+
}
27+
prev_msg_ = msg;
28+
})},
29+
client_{node_.create_client<zigros_example_interface::srv::Example>("example")}
30+
{
31+
}
32+
} // namespace zigros_examples

0 commit comments

Comments
 (0)