Skip to content

Commit ca78714

Browse files
pablogs9jamoralp
andauthored
Add external transport example (#37)
* Initial Rolling support Update client Update Update * Initial * Add custom transport example * Update * Fix CI * Fix CI: fix checkout path * Update .github/workflows/ci.yml Co-authored-by: Jose Antonio Moral <joseantoniomoralparras@gmail.com>
1 parent 88d01b5 commit ca78714

12 files changed

Lines changed: 261 additions & 14 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ jobs:
2424
rm -rf src/uros/micro-ROS-demos
2525
- uses: actions/checkout@v2
2626
with:
27-
path: src/uros/micro-ROS-demos
27+
path: uros_ws/src/uros/micro-ROS-demos
2828
- name: Build
2929
run: |
3030
cd /uros_ws
3131
source /opt/ros/foxy/setup.bash
3232
source install/local_setup.bash
33-
ros2 run micro_ros_setup build_firmware.sh
33+
ros2 run micro_ros_setup build_firmware.sh

rclc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export_executable(timer)
5151
export_executable(string_publisher)
5252
export_executable(string_subscriber)
5353
export_executable(autodiscover_agent)
54+
export_executable(configuration_example custom_transports)
5455

5556
if(EXISTS ${CMAKE_BINARY_DIR}/temp_install/)
5657
install(

rclc/addtwoints_client/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
example_interfaces__srv__AddTwoInts_Request req;
1515
example_interfaces__srv__AddTwoInts_Response res;
1616

17-
void client_callback(const void * msg, rmw_request_id_t * req_id){
17+
void client_callback(const void * msg){
1818
example_interfaces__srv__AddTwoInts_Response * msgin = (example_interfaces__srv__AddTwoInts_Response * ) msg;
19-
printf("Received service response %ld + %ld = %ld. Seq %ld\n", req.a, req.b, msgin->sum, req_id->sequence_number);
19+
printf("Received service response %ld + %ld = %ld\n", req.a, req.b, msgin->sum);
2020
}
2121

2222
int main(int argc, const char * const * argv)

rclc/autodiscover_agent/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ find_package(rcl REQUIRED)
77
find_package(rclc REQUIRED)
88
find_package(std_msgs REQUIRED)
99
find_package(rmw_microxrcedds REQUIRED)
10+
find_package(microxrcedds_client REQUIRED)
1011

1112
add_executable(${PROJECT_NAME} main.c)
1213

14+
target_link_libraries(${PROJECT_NAME}
15+
microxrcedds_client
16+
)
17+
1318
ament_target_dependencies(${PROJECT_NAME}
1419
rcl
1520
rclc
1621
std_msgs
1722
rmw_microxrcedds
23+
microxrcedds_client
1824
)
1925

2026
install(TARGETS ${PROJECT_NAME}

rclc/configuration_example/configured_publisher/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ find_package(rcl REQUIRED)
77
find_package(rclc REQUIRED)
88
find_package(std_msgs REQUIRED)
99
find_package(rmw_microxrcedds REQUIRED)
10+
find_package(microxrcedds_client REQUIRED)
1011

1112
add_executable(${PROJECT_NAME} main.c)
1213

14+
target_link_libraries(${PROJECT_NAME}
15+
microxrcedds_client
16+
)
17+
1318
ament_target_dependencies(${PROJECT_NAME}
1419
rcl
1520
rclc
1621
std_msgs
1722
rmw_microxrcedds
23+
microxrcedds_client
1824
)
1925

2026
install(TARGETS ${PROJECT_NAME}

rclc/configuration_example/configured_publisher/main.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,18 @@ int main(int argc, char * const argv[])
4343
RCCHECK(rmw_uros_options_set_udp_address(argv[1], argv[2], rmw_options))
4444
RCCHECK(rmw_uros_options_set_client_key(0xCAFEBABA, rmw_options))
4545

46+
size_t domain_id = (size_t)(argc == 4 ? atoi(argv[3]) : 0);
47+
const char * node_name = "int32_configured_publisher_rclc";
48+
49+
rcl_init_options_set_domain_id(&init_options, domain_id);
50+
printf("Initializing RCL '%s' with ROS Domain ID %ld...\n", node_name, domain_id);
51+
4652
// create init_options
4753
RCCHECK(rclc_support_init_with_options(&support, 0, NULL, &init_options, &allocator));
4854

4955
// create node
5056
rcl_node_t node = rcl_get_zero_initialized_node();
51-
rcl_node_options_t node_ops = rcl_node_get_default_options();
52-
node_ops.domain_id = (size_t)(argc == 4 ? atoi(argv[3]) : 0);
53-
const char * node_name = "int32_configured_publisher_rclc";
54-
printf("Initializing node '%s' with ROS Domain ID %ld...\n",node_name, node_ops.domain_id);
55-
RCCHECK(rclc_node_init_with_options(&node, node_name, "", &support, &node_ops));
57+
RCCHECK(rclc_node_init_default(&node, node_name, "", &support));
5658

5759
// create publisher
5860
RCCHECK(rclc_publisher_init_default(

rclc/configuration_example/configured_subscriber/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ find_package(rcl REQUIRED)
77
find_package(rclc REQUIRED)
88
find_package(std_msgs REQUIRED)
99
find_package(rmw_microxrcedds REQUIRED)
10+
find_package(microxrcedds_client REQUIRED)
1011

1112
add_executable(${PROJECT_NAME} main.c)
1213

14+
target_link_libraries(${PROJECT_NAME}
15+
microxrcedds_client
16+
)
17+
1318
ament_target_dependencies(${PROJECT_NAME}
1419
rcl
1520
rclc
1621
std_msgs
1722
rmw_microxrcedds
23+
microxrcedds_client
1824
)
1925

2026
install(TARGETS ${PROJECT_NAME}

rclc/configuration_example/configured_subscriber/main.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,18 @@ int main(int argc, const char * const * argv)
3939
RCCHECK(rmw_uros_options_set_udp_address(argv[1], argv[2], rmw_options))
4040
RCCHECK(rmw_uros_options_set_client_key(0xCAFEBABE, rmw_options))
4141

42+
size_t domain_id = (size_t)(argc == 4 ? atoi(argv[3]) : 0);
43+
const char * node_name = "int32_configured_subscriber_rclc";
44+
45+
rcl_init_options_set_domain_id(&init_options, domain_id);
46+
printf("Initializing RCL '%s' with ROS Domain ID %ld...\n", node_name, domain_id);
47+
4248
// create init_options
4349
RCCHECK(rclc_support_init_with_options(&support, 0, NULL, &init_options, &allocator));
4450

4551
// create node
4652
rcl_node_t node = rcl_get_zero_initialized_node();
47-
rcl_node_options_t node_ops = rcl_node_get_default_options();
48-
node_ops.domain_id = (size_t)(argc == 4 ? atoi(argv[3]) : 0);
49-
const char * node_name = "int32_configured_subscriber_rclc";
50-
printf("Initializing node '%s' with ROS Domain ID %ld...\n", node_name, node_ops.domain_id);
51-
RCCHECK(rclc_node_init_with_options(&node, node_name, "", &support, &node_ops));
53+
RCCHECK(rclc_node_init_default(&node, node_name, "", &support));
5254

5355
// create subscriber
5456
RCCHECK(rclc_subscription_init_default(
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
cmake_minimum_required(VERSION 3.5)
2+
3+
project(custom_transports LANGUAGES C)
4+
5+
find_package(ament_cmake REQUIRED)
6+
find_package(rcl REQUIRED)
7+
find_package(rclc REQUIRED)
8+
find_package(std_msgs REQUIRED)
9+
find_package(rmw_microxrcedds REQUIRED)
10+
find_package(microxrcedds_client REQUIRED)
11+
12+
add_executable(${PROJECT_NAME} main.c)
13+
14+
target_link_libraries(${PROJECT_NAME}
15+
microxrcedds_client
16+
)
17+
18+
ament_target_dependencies(${PROJECT_NAME}
19+
rcl
20+
rclc
21+
std_msgs
22+
rmw_microxrcedds
23+
microxrcedds_client
24+
)
25+
26+
set_target_properties(${PROJECT_NAME} PROPERTIES
27+
CXX_STANDARD
28+
11
29+
CXX_STANDARD_REQUIRED
30+
YES
31+
)
32+
33+
install(TARGETS ${PROJECT_NAME}
34+
DESTINATION ${PROJECT_NAME}
35+
)
36+
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#include <rcl/rcl.h>
2+
#include <rcl/error_handling.h>
3+
#include <rclc/rclc.h>
4+
#include <rclc/executor.h>
5+
6+
#include <std_msgs/msg/int32.h>
7+
8+
#include <sys/types.h>
9+
#include <sys/socket.h>
10+
#include <poll.h>
11+
#include <stdio.h>
12+
#include <stdint.h>
13+
#include <unistd.h>
14+
#include <fcntl.h>
15+
#include <sys/socket.h>
16+
#include <arpa/inet.h>
17+
#include <string.h>
18+
#include <errno.h>
19+
#include <netdb.h>
20+
21+
#include <rmw_uros/options.h>
22+
23+
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc); return 1;}}
24+
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}}
25+
26+
// --- micro-ROS Transports ---
27+
28+
typedef struct {
29+
struct pollfd poll_fd;
30+
} custom_transport_data_t;
31+
32+
bool custom_transport_open(struct uxrCustomTransport * transport){
33+
custom_transport_data_t * transport_data = (custom_transport_data_t*) transport->args;
34+
35+
bool rv = false;
36+
transport_data->poll_fd.fd = socket(AF_INET, SOCK_DGRAM, 0);
37+
38+
if (-1 != transport_data->poll_fd.fd)
39+
{
40+
struct addrinfo hints;
41+
struct addrinfo* result;
42+
struct addrinfo* ptr;
43+
44+
memset(&hints, 0, sizeof(hints));
45+
hints.ai_family = AF_INET;
46+
hints.ai_socktype = SOCK_DGRAM;
47+
48+
if (0 == getaddrinfo("localhost", "8888", &hints, &result))
49+
{
50+
for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
51+
{
52+
if (0 == connect(transport_data->poll_fd.fd, ptr->ai_addr, ptr->ai_addrlen))
53+
{
54+
transport_data->poll_fd.events = POLLIN;
55+
rv = true;
56+
break;
57+
}
58+
}
59+
}
60+
freeaddrinfo(result);
61+
}
62+
return rcutils_vsnprintf;
63+
}
64+
65+
bool custom_transport_close(struct uxrCustomTransport * transport){
66+
custom_transport_data_t * transport_data = (custom_transport_data_t*) transport->args;
67+
return (-1 == transport_data->poll_fd.fd) ? true : (0 == close(transport_data->poll_fd.fd));
68+
}
69+
70+
size_t custom_transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * errcode){
71+
custom_transport_data_t * transport_data = (custom_transport_data_t*) transport->args;
72+
size_t rv = 0;
73+
ssize_t bytes_sent = send(transport_data->poll_fd.fd, (void*)buf, len, 0);
74+
if (-1 != bytes_sent)
75+
{
76+
rv = (size_t)bytes_sent;
77+
*errcode = 0;
78+
}
79+
else
80+
{
81+
*errcode = 1;
82+
}
83+
return rv;
84+
}
85+
86+
size_t custom_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* errcode){
87+
custom_transport_data_t * transport_data = (custom_transport_data_t*) transport->args;
88+
size_t rv = 0;
89+
int poll_rv = poll(&transport_data->poll_fd, 1, timeout);
90+
if (0 < poll_rv)
91+
{
92+
ssize_t bytes_received = recv(transport_data->poll_fd.fd, (void*)buf, len, 0);
93+
if (-1 != bytes_received)
94+
{
95+
rv = (size_t)bytes_received;
96+
*errcode = 0;
97+
}
98+
else
99+
{
100+
*errcode = 1;
101+
}
102+
}
103+
else
104+
{
105+
*errcode = (0 == poll_rv) ? 0 : 1;
106+
}
107+
return rv;
108+
}
109+
110+
111+
// --- micro-ROS App ---
112+
113+
rcl_publisher_t publisher;
114+
std_msgs__msg__Int32 msg;
115+
116+
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
117+
{
118+
(void) last_call_time;
119+
if (timer != NULL) {
120+
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
121+
printf("Sent: %d\n", msg.data);
122+
msg.data++;
123+
}
124+
}
125+
126+
int main(int argc, char * const argv[])
127+
{
128+
rcl_allocator_t allocator = rcl_get_default_allocator();
129+
rclc_support_t support;
130+
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
131+
132+
RCCHECK(rcl_init_options_init(&init_options, allocator));
133+
rmw_init_options_t* rmw_options = rcl_init_options_get_rmw_init_options(&init_options);
134+
RCCHECK(rmw_uros_options_set_client_key(0xCAFEBABA, rmw_options))
135+
136+
custom_transport_data_t custom_transport_data;
137+
138+
RCCHECK(rmw_uros_options_set_custom_transport(
139+
false,
140+
(void*) &custom_transport_data,
141+
custom_transport_open,
142+
custom_transport_close,
143+
custom_transport_write,
144+
custom_transport_read,
145+
rmw_options
146+
))
147+
148+
// create init_options
149+
RCCHECK(rclc_support_init_with_options(&support, 0, NULL, &init_options, &allocator));
150+
151+
// create node
152+
rcl_node_t node = rcl_get_zero_initialized_node();
153+
RCCHECK(rclc_node_init_default(&node, "custom_transport_node", "", &support));
154+
155+
// create publisher
156+
RCCHECK(rclc_publisher_init_default(
157+
&publisher,
158+
&node,
159+
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
160+
"std_msgs_msg_Int32"));
161+
162+
// create timer,
163+
rcl_timer_t timer = rcl_get_zero_initialized_timer();
164+
const unsigned int timer_timeout = 1000;
165+
RCCHECK(rclc_timer_init_default(
166+
&timer,
167+
&support,
168+
RCL_MS_TO_NS(timer_timeout),
169+
timer_callback));
170+
171+
// create executor
172+
rclc_executor_t executor = rclc_executor_get_zero_initialized_executor();
173+
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
174+
RCCHECK(rclc_executor_add_timer(&executor, &timer));
175+
176+
msg.data = 0;
177+
178+
rclc_executor_spin(&executor);
179+
180+
RCCHECK(rcl_publisher_fini(&publisher, &node));
181+
RCCHECK(rcl_node_fini(&node));
182+
183+
return 0;
184+
}

0 commit comments

Comments
 (0)