参考以往部分历程:
1. esp32与ros2的欢乐启程 2021
2. micro-ROS之esp32与ros2资料(freertos) 2021
3. esp32发布机器人电池电压到ros2(micro-ros+CoCube) 2022
4. CoCube和Micro-ROS简单案例演示 2022
不需要僵化的区分ROS1和ROS2,借助人工智能工具,提出需求让AI解决就好。
M5ATOMS3基础03给ROS1发一个问候(rosserial)
ROS1使用:
- rosserial
ROS2使用:
- micro-ROS
这两种方式并不是唯一的,但是最为方便,网络上资料多,AI也熟悉并且能写出没有错误的代码。
2023年,使用端口号2023
./MicroXRCEAgent udp4 -p 2023
连接M5AtomS3成功后会显示:
下面资料提供给人工智能,让它完成代码就好。
#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/int32.h>
rcl_publisher_t publisher;
std_msgs__msg__Int32 msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
#define LED_PIN 13
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}
void error_loop(){
while(1){
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
msg.data++;
}
}
void setup() {
set_microros_transports();
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
delay(2000);
allocator = rcl_get_default_allocator();
//create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support));
// create publisher
RCCHECK(rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
"micro_ros_arduino_node_publisher"));
// create timer,
const unsigned int timer_timeout = 1000;
RCCHECK(rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback));
// create executor
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor, &timer));
msg.data = 0;
}
void loop() {
delay(100);
RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)));
}
这段代码是一个使用MicroROS的Arduino库来创建一个ROS节点并发布一个整数消息的示例。
首先,代码包含了一些必要的头文件,包括micro_ros_arduino.h、stdio.h、rcl.h、rclc.h、std_msgs.h等。
然后,定义了一些全局变量,包括publisher、msg、executor、support、allocator、node和timer,这些变量将在后面的函数中使用。
接下来,定义了一些宏函数,包括RCCHECK和RCsoftCHECK,用于检查ROS函数的返回值并处理错误。
然后,定义了一个error_loop函数,用于在出现错误时进入一个无限循环,通过LED的开关状态来指示错误状态。
在setup函数中,进行一些初始化设置。首先,设置MicroROS传输层。然后,设置LED引脚为输出模式,并初始化为高电平。
之后,延迟2秒钟,然后初始化ROS相关组件。首先,获取默认分配器。然后,使用rclc_support_init函数初始化support。接下来,使用rclc_node_init_default函数创建节点。然后,使用rclc_publisher_init_default函数创建发布者,并指定消息类型和话题名称。接着,使用rclc_timer_init_default函数创建计时器,并指定回调函数和超时时间。最后,使用rclc_executor_init函数初始化执行器,并使用rclc_executor_add_timer函数将计时器添加到执行器中。
在loop函数中,延迟100毫秒,然后使用rclc_executor_spin_some函数让执行器处理一些消息。
总体而言,这段代码创建了一个ROS节点,该节点每秒发布一个整数消息,并通过LED的开关状态来显示发布的状态。
然后,让人工智能完成字符串发送的代码。
#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/string.h>
rcl_publisher_t publisher;
std_msgs__msg__String msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
#define LED_PIN 13
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}
void error_loop(){
while(1){
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
msg.data = "Hello ROS!";
}
}
void setup() {
set_microros_transports();
pinMode(LED_PIN, Output);
digitalWrite(LED_PIN, HIGH);
delay(2000);
allocator = rcl_get_default_allocator();
//create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support));
// create publisher
RCCHECK(rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String),
"micro_ros_arduino_node_publisher"));
// create timer,
const unsigned int timer_timeout = 1000;
RCCHECK(rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback));
// create executor
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor, &timer));
msg.data = "";
}
void loop() {
delay(100);
RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)));
}#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/string.h>
rcl_publisher_t publisher;
std_msgs__msg__String msg;
rclc_executor_t executor;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
#define LED_PIN 13
#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){error_loop();}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){}}
void error_loop(){
while(1){
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
RCLC_UNUSED(last_call_time);
if (timer != NULL) {
RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
msg.data = "Hello ROS!";
}
}
void setup() {
set_microros_transports();
pinMode(LED_PIN, Output);
digitalWrite(LED_PIN, HIGH);
delay(2000);
allocator = rcl_get_default_allocator();
//create init_options
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
// create node
RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_node", "", &support));
// create publisher
RCCHECK(rclc_publisher_init_default(
&publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String),
"micro_ros_arduino_node_publisher"));
// create timer,
const unsigned int timer_timeout = 1000;
RCCHECK(rclc_timer_init_default(
&timer,
&support,
RCL_MS_TO_NS(timer_timeout),
timer_callback));
// create executor
RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor, &timer));
msg.data = "";
}
void loop() {
delay(100);
RCSOFTCHECK(rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)));
}
这个示例与之前的示例类似,不同之处在于发布者发布的是字符串消息而不是整数消息。在timer回调函数中,我们将字符串消息的数据设置为"Hello ROS!",然后进行发布。其他部分与之前的示例相同。
并不准确的AI总结
在MicroROS与ROS2之间进行通信时,需要注意以下事项:
- 兼容性:MicroROS和ROS2在消息传递和通信方面有所不同,因此需要确保两者之间的兼容性。在编写节点时,需要使用兼容的通信库和API。
- 通信协议:MicroROS和ROS2使用不同的通信协议。因此,在通信过程中,需要确保使用正确的通信协议进行消息传递。
- 消息格式:MicroROS和ROS2使用的消息格式可能不同。在通信过程中,需要确保消息格式的正确性,以便正确解析和传递消息。
- 节点间互操作性:MicroROS和ROS2之间的节点可能具有不同的功能和能力。在通信过程中,需要确保节点之间的互操作性,以便正确地交换数据和服务。
- 数据同步:如果MicroROS和ROS2之间存在数据同步的需求,需要确保数据在正确的时间和顺序进行传递和更新。
- 错误处理:在通信过程中,可能会出现各种错误和异常情况。因此,需要适当的处理和记录这些错误,以确保系统的正常运行。
- 跨平台支持:MicroROS和ROS2都可以在不同的操作系统和平台上运行。在通信过程中,需要考虑跨平台支持,以确保通信的稳定性和可靠性。
综上所述,在进行MicroROS与ROS2之间的通信时,需要注意这些事项,以确保通信的正确性和可靠性。
ESP32是一种嵌入式系统开发板,具有强大的处理能力和丰富的的学习资源。在ROS(机器人操作系统)通信方面,它可以同时支持ROS1和MicroROS与ROS2之间的通信。下面将比较这三种通信方式之间的差异:
1 ROS1与MicroROS
ROS1是早期的ROS版本,使用master仲裁机制进行通信。它不支持跨网络通信,因此需要使用ROS自带的ROS Master来实现节点之间的通信。而MicroROS是ROS的精简版本,专门为嵌入式系统设计,具有更小的内存占用和更快的运行速度。它支持跨网络通信,可以使用多种通信协议进行节点之间的通信。
2 MicroROS与ROS2
ROS2是ROS的最新版本,引入了新的通信机制,包括数据分发和服务质量(QoS)。它支持跨网络通信,具有更好的可靠性和实时性。MicroROS与ROS2之间的主要区别在于通信协议和QoS的支持。MicroROS使用基于UDP的通信协议,而ROS2支持多种通信协议,包括TCP和UDP。此外,MicroROS不支持QoS,而ROS2可以根据需要选择不同的QoS等级。
3 ESP32与ROSSerial
rosserial是ROS的一个串口库,可以在ESP32等嵌入式系统中使用。它支持通过串口与ROS节点进行通信,并可以进行消息的发布和订阅。在ESP32上使用rosserial进行通信时,需要配置串口参数和波特率,以确保与ROS Master的正常通信。
综上所述,ESP32可以使用rosserial与ROS1通信,使用MicroROS与ROS2通信。虽然这三种通信方式之间存在一些差异,但都可以实现ESP32与ROS节点之间的通信。选择哪种通信方式取决于具体应用场景和需求,例如对通信实时性、可靠性和网络的要求等。
Micro-ROS其实是支持QoS的。
The DDS-XRCE wire protocol is specified to be in at least TCP and UDP transport protocol, but there is room to expand to other protocols. Currently, implementations are supporting Serial links and possible to be extended to any other such Zigbee, 6LoWPAN, and more. DDS-XRCE allows setting two different delivery QoS:
- Reliable.
- Best-effort.