Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.

Commit 56cb5e9

Browse files
authored
Added ping_pong example (#23)
* Added ping_pong example * Update * Migrated ping_pong to RCLC * Update apps * Fix colcon metas * FIx kconfig * Updates * Working pingpong * Migrate to RCLC
1 parent 5187d6e commit 56cb5e9

10 files changed

Lines changed: 202 additions & 14 deletions

File tree

examples/kobuki/kobuki_main.cxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
// for time ??? #include "builtin_interfaces/msg/time__struct.h"
5858

5959
// strings in imu message : frame_id
60-
#include "rosidl_generator_c/string.h"
6160

6261
#include "kobuki_robot.h"
6362

examples/kobuki/kobuki_node.cxx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232

3333
#include "uros/ros_util.h"
3434
#include "kobuki_node.h"
35-
#include <rosidl_generator_c/string_functions.h>
36-
#include <rosidl_generator_c/primitives_sequence_functions.h>
3735

3836
static const float NOMINAL_BATTERY_VOLTAGE = 16.7f;
3937

examples/publisher/publisher_main.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,22 @@ int main(int argc, char *argv[])
99
#else
1010
int publisher_main(int argc, char* argv[])
1111
#endif
12-
{
12+
{
1313
rcl_ret_t rv;
1414

1515
rcl_init_options_t options = rcl_get_zero_initialized_init_options();
1616
rv = rcl_init_options_init(&options, rcl_get_default_allocator());
17+
printf("rcl_init_options_init\n");
18+
1719
if (RCL_RET_OK != rv) {
1820
printf("rcl init options error: %s\n", rcl_get_error_string().str);
1921
return 1;
2022
}
2123

2224
rcl_context_t context = rcl_get_zero_initialized_context();
2325
rv = rcl_init(argc, argv, &options, &context);
26+
printf("rcl_init\n");
27+
2428
if (RCL_RET_OK != rv) {
2529
printf("rcl initialization error: %s\n", rcl_get_error_string().str);
2630
return 1;

examples/uros_pingpong/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
config UROS_PINGPONG_EXAMPLE
2+
bool "micro-ROS Ping Pong"
3+
default n
4+
depends on UROS
5+
---help---
6+
micro-ROS Ping Pong sample app
7+
8+
if UROS_PINGPONG_EXAMPLE
9+
10+
config UROS_PINGPONG_EXAMPLE_PROGNAME
11+
string "Program name"
12+
default "uros_ping_pong"
13+
depends on BUILD_KERNEL
14+
---help---
15+
This is the name of the program that will be use when the NSH ELF
16+
program is installed.
17+
18+
endif

examples/uros_pingpong/Make.defs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ifeq ($(CONFIG_UROS_PINGPONG_EXAMPLE),y)
2+
CONFIGURED_APPS += examples/uros_pingpong
3+
endif

examples/uros_pingpong/Makefile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-include $(TOPDIR)/Make.defs
2+
3+
#Set the scheduler priority for the app.
4+
CONFIG_UROS_PINGPONG_EXAMPLE_PRIORITY ?= SCHED_PRIORITY_DEFAULT
5+
#Set the stack size to the app. The minimum stack size on NuttX for a micro-ROS App is 65000 bytes
6+
CONFIG_UROS_PINGPONG_EXAMPLE_STACKSIZE ?= 65000
7+
8+
#This is the name of the app on the NSH console
9+
APPNAME = uros_pingpong
10+
PRIORITY = $(CONFIG_UROS_PINGPONG_EXAMPLE_PRIORITY)
11+
STACKSIZE = $(CONFIG_UROS_PINGPONG_EXAMPLE_STACKSIZE)
12+
13+
#Add the source files.
14+
ASRCS =
15+
CSRCS =
16+
MAINSRC = app.c
17+
18+
CONFIG_UROS_PINGPONG_EXAMPLE_PROGNAME ?= uros_pingpong$(EXEEXT)
19+
PROGNAME = $(CONFIG_UROS_PINGPONG_EXAMPLE_PROGNAME)
20+
UROS_PINGPONG_INCLUDES = $(shell find $(APPDIR)/$(CONFIG_UROS_DIR)/install -type d -name include)
21+
CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" "$(UROS_PINGPONG_INCLUDES)"} -std=c99
22+
23+
MODULE = CONFIG_UROS_PINGPONG_EXAMPLE
24+
25+
include $(APPDIR)/Application.mk

examples/uros_pingpong/app.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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/header.h>
7+
8+
#include <stdio.h>
9+
#include <unistd.h>
10+
#include <time.h>
11+
12+
#define STRING_BUFFER_LEN 100
13+
14+
#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;}}
15+
#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);}}
16+
17+
rcl_publisher_t ping_publisher;
18+
rcl_publisher_t pong_publisher;
19+
rcl_subscription_t ping_subscriber;
20+
rcl_subscription_t pong_subscriber;
21+
22+
std_msgs__msg__Header incoming_ping;
23+
std_msgs__msg__Header outcoming_ping;
24+
std_msgs__msg__Header incoming_pong;
25+
26+
int device_id;
27+
int seq_no;
28+
int pong_count;
29+
30+
void ping_timer_callback(rcl_timer_t * timer, int64_t last_call_time)
31+
{
32+
(void) last_call_time;
33+
34+
if (timer != NULL) {
35+
36+
seq_no = rand();
37+
sprintf(outcoming_ping.frame_id.data, "%d_%d", seq_no, device_id);
38+
outcoming_ping.frame_id.size = strlen(outcoming_ping.frame_id.data);
39+
40+
// Fill the message timestamp
41+
struct timespec ts;
42+
clock_gettime(CLOCK_REALTIME, &ts);
43+
outcoming_ping.stamp.sec = ts.tv_sec;
44+
outcoming_ping.stamp.nanosec = ts.tv_nsec;
45+
46+
// Reset the pong count and publish the ping message
47+
pong_count = 0;
48+
rcl_publish(&ping_publisher, (const void*)&outcoming_ping, NULL);
49+
printf("Ping send seq %s\n", outcoming_ping.frame_id.data);
50+
}
51+
}
52+
53+
void ping_subscription_callback(const void * msgin)
54+
{
55+
const std_msgs__msg__Header * msg = (const std_msgs__msg__Header *)msgin;
56+
57+
// Dont pong my own pings
58+
if(strcmp(outcoming_ping.frame_id.data, msg->frame_id.data) != 0){
59+
printf("Ping received with seq %s. Answering.\n", msg->frame_id.data);
60+
rcl_publish(&pong_publisher, (const void*)msg, NULL);
61+
}
62+
}
63+
64+
65+
void pong_subscription_callback(const void * msgin)
66+
{
67+
const std_msgs__msg__Header * msg = (const std_msgs__msg__Header *)msgin;
68+
69+
if(strcmp(outcoming_ping.frame_id.data, msg->frame_id.data) == 0) {
70+
pong_count++;
71+
printf("Pong for seq %s (%d)\n", msg->frame_id.data, pong_count);
72+
}
73+
}
74+
75+
76+
#if defined(BUILD_MODULE)
77+
int main(int argc, char *argv[])
78+
#else
79+
int uros_pingpong_main(int argc, char* argv[])
80+
#endif
81+
{
82+
rcl_allocator_t allocator = rcl_get_default_allocator();
83+
rclc_support_t support;
84+
85+
// create init_options
86+
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
87+
88+
// create node
89+
rcl_node_t node = rcl_get_zero_initialized_node();
90+
RCCHECK(rclc_node_init_default(&node, "pingpong_node", "", &support));
91+
92+
// Create a reliable ping publisher
93+
RCCHECK(rclc_publisher_init_default(&ping_publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Header), "/microROS/ping"));
94+
95+
// Create a best effort pong publisher
96+
RCCHECK(rclc_publisher_init_best_effort(&pong_publisher, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Header), "/microROS/pong"));
97+
98+
// Create a best effort ping subscriber
99+
RCCHECK(rclc_subscription_init_best_effort(&ping_subscriber, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Header), "/microROS/ping"));
100+
101+
// Create a best effort pong subscriber
102+
RCCHECK(rclc_subscription_init_best_effort(&pong_subscriber, &node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Header), "/microROS/pong"));
103+
104+
105+
// Create a 3 seconds ping timer timer,
106+
rcl_timer_t timer = rcl_get_zero_initialized_timer();
107+
RCCHECK(rclc_timer_init_default(&timer, &support, RCL_MS_TO_NS(2000), ping_timer_callback));
108+
109+
110+
// Create executor
111+
rclc_executor_t executor = rclc_executor_get_zero_initialized_executor();
112+
RCCHECK(rclc_executor_init(&executor, &support.context, 3, &allocator));
113+
114+
unsigned int rcl_wait_timeout = 1000; // in ms
115+
RCCHECK(rclc_executor_set_timeout(&executor, RCL_MS_TO_NS(rcl_wait_timeout)));
116+
RCCHECK(rclc_executor_add_timer(&executor, &timer));
117+
RCCHECK(rclc_executor_add_subscription(&executor, &ping_subscriber, &incoming_ping, &ping_subscription_callback, ON_NEW_DATA));
118+
RCCHECK(rclc_executor_add_subscription(&executor, &pong_subscriber, &incoming_pong, &pong_subscription_callback, ON_NEW_DATA));
119+
120+
// Create and allocate the pingpong messages
121+
122+
char outcoming_ping_buffer[STRING_BUFFER_LEN];
123+
outcoming_ping.frame_id.data = outcoming_ping_buffer;
124+
outcoming_ping.frame_id.capacity = STRING_BUFFER_LEN;
125+
126+
char incoming_ping_buffer[STRING_BUFFER_LEN];
127+
incoming_ping.frame_id.data = incoming_ping_buffer;
128+
incoming_ping.frame_id.capacity = STRING_BUFFER_LEN;
129+
130+
char incoming_pong_buffer[STRING_BUFFER_LEN];
131+
incoming_pong.frame_id.data = incoming_pong_buffer;
132+
incoming_pong.frame_id.capacity = STRING_BUFFER_LEN;
133+
134+
device_id = rand();
135+
136+
rclc_executor_spin(&executor);
137+
138+
RCCHECK(rcl_publisher_fini(&ping_publisher, &node));
139+
RCCHECK(rcl_publisher_fini(&pong_publisher, &node));
140+
RCCHECK(rcl_subscription_fini(&ping_subscriber, &node));
141+
RCCHECK(rcl_subscription_fini(&pong_subscriber, &node));
142+
RCCHECK(rcl_node_fini(&node));
143+
}

examples/uros_pong_server/pong_server.cxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "pong_server.h"
2-
#include "rosidl_generator_c/string_functions.h"
32
#include <sstream>
43

54
using namespace kobuki;

uros/Kconfig

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ endif
4949
if UROS_TRANSPORT_SERIAL
5050
config UROS_SERIAL_PORT
5151
string "Serial port to use"
52-
default "/dev/ttyS1"
52+
default "/dev/ttyS0"
5353

5454
endif
5555

@@ -58,21 +58,21 @@ config UROS_MAX_NODES
5858
default 2
5959

6060
config UROS_MAX_PUBLISHERS
61-
int "Maximum number of publishers per node"
61+
int "Maximum number of publishers"
6262
default 2
6363

6464
config UROS_MAX_SUBSCRIPTIONS
65-
int "Maximum number of subscriptions per node"
66-
default 1
65+
int "Maximum number of subscriptions"
66+
default 2
6767

6868
config UROS_MAX_SERVICES
69-
int "Maximum number of service handlers per node"
69+
int "Maximum number of service handlers"
7070
default 1
7171
---help---
72-
This is the maximum number of services per node. Please note that parameter service, if used, needs one of those.
72+
This is the maximum number of services. Please note that parameter service, if used, needs one of those.
7373

7474
config UROS_MAX_CLIENTS
75-
int "Maximum number of service clients per node"
75+
int "Maximum number of service clients"
7676
default 1
7777

7878
config UROS_MAX_HISTORY

uros/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ colcon_compile: arm_toolchain.cmake rmw_config.meta
5959
$(Q) cd $(UROS_DIR); \
6060
colcon build \
6161
--packages-ignore-regex=.*_cpp \
62-
--metas colcon.meta \
63-
--metas $(APPDIR)/uros/rmw_config.meta \
62+
--metas $(UROS_DIR)/colcon.meta $(APPDIR)/uros/rmw_config.meta \
6463
--cmake-args \
6564
-DBUILD_SHARED_LIBS=OFF \
6665
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \

0 commit comments

Comments
 (0)