目录
1、前言
2、内容
2.1 准备工作
2.1.1 连接外部USB设备
2.1.2 串口调试工具的下载
2.1.3 serial库的安装
2.2 代码部分
2.2.1 编写发布节点
2.2.2 编写发布节点
2.2.3 编辑checklists文件
2.2.4 编辑package.xml文件
2.2.5 编写launch文件
2.2.6 运行节点
3 可能的问题
引用
最近项目中有一个需求,在ROS2的环境下,需要接受到两个topic,作出逻辑判断,通过串口发送特定报文到外接USB设备上。之前在论坛中找了好久没有类似的文章,因此在这里记录一下,同学们可以参考,其中如果有问题或者可以优化的地方,欢迎大家指正。
由于我使用的是ros2的humble版本,因此一下工作环境皆为ubuntu22.04版本以及ROS2的humble版本。该部分工作在代码编写之前就需要准备好。
在调试之前建议链接USB设备,一并查看系统上是否有串口驱动,通常ubuntu系统已经集成了串口驱动:s541,可以通过以下命令行来查看:
lsmod | grep usbserial
出现一下类似情况说明驱动已经存在
此刻通过频繁插拔外界设备,之后通过下述命令进行判断该设备串口名称
dmesg| grep ttyU*
对话框中会弹出很多内容,找到频繁出现“conect”和“disconect”的便是我们想要的串口。
在此我们安装使用的是cutecom工具,安装命令见下:
sudo apt-get install cutecom
在使用时可以通过以下命令打开:
sudo cutecom
打开界面见下:
可以在setting部分进行串口参数的配置,这里的将要采用的配置为:9600 8 n 1。
为了完成ros和外界设备的通讯,还需要安装serial库文件,由于ros2中没有集成serial库,因此需要自己下载源码进行编译安装。btw,ros中可以直接通过apt-get进行安装的,这个我会再写一份文章。
该库虽然是针对foxy的,但是在humble中也可以使用,通过一下进行clone和编译
mkdir serial
git clone https://github.com/ZhaoXiangBox/serial
cd serial
mkdir build
cmake ..
make
此刻基本上已经安装编译好了。
截至目前位置,我们已经完成了一切准备工作,下面开始进行代码部分。
我们首先整理一下需求:
1、接收两个topic;
2、根据topic内容进行逻辑判断;
3、根据判断结果,发送16进制的8个byte的报文到设备;
在正式编写代码之前,首先先建立一下ros2的工作空间和工作包
mkdir -p ~/ros2/src
cd ~/ros2/src
ros2 pkg create --build-type ament_cmake demo
以上代码意为,建立一个名字叫做demo的功能包使用c++进行编写。
首先编写一个节点
cd ~/ros2/src/demo/src
touch talker.cpp
之后编写代码,talker节点会根据键盘的指令输入0或者1。
#include
#include
#include
#include
#include "sensor_msgs/msg/image.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
int a = 0;
auto message = sensor_msgs::msg::Image();
int func(0);
std::cout << "请输入数字";
std::cin >> func;
switch (func)
{
case 0:
a = 0;
break;
case 1:
a = 4;
break;
}
message.height = a;
publisher_->publish(message);
// std::cout << message.height << std::endl;
RCLCPP_INFO(get_logger(), "参数1:%d", message.height);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared());
rclcpp::shutdown();
return 0;
}
通过以上方式在建立一个talker1,talker1会持续发送数字4.
#include
#include
#include
#include
#include "sensor_msgs/msg/image.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher1"), count_(0)
{
publisher_ = this->create_publisher("topic1", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
// int a = 0;
auto message = sensor_msgs::msg::Image();
message.height = 4;
publisher_->publish(message);
std::cout << message.height << std::endl;
RCLCPP_INFO(get_logger(),"参数2:%d",message.height);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared());
rclcpp::shutdown();
return 0;
}
这样,两个发布节点编写完毕。
首先需要接受两个节点的话题,并作逻辑处理,之后使用serial库文件的函数进行数据的发送,目前我们的设备可以通过不同的报文开灯和关灯,发送报文: 0x01,0x05,0x0,0x02,0x00,0x00,0x6C,0x0A;为开灯。0x01,0x05,0x0,0x02,0xff,0x00,0x2D,0xFA;为关灯。
建立可执行文件
cd ~/ros2/src/demo/src
touch lis.cpp
以下是具体代码。
#include
#include
#include
#include "serial/serial.h"
#include "rclcpp/rclcpp.hpp"
#include "message_filters/subscriber.h"
#include "message_filters/time_synchronizer.h"
#include "sensor_msgs/msg/image.hpp"
using std::placeholders::_1;
using std::placeholders::_2;
serial::Serial ros_ser;
class MinimalSubscriber : public rclcpp::Node
{
public:
MinimalSubscriber()
: Node("minimal_sync_subscriber")
{
sub1_.subscribe(this, "topic");
sub2_.subscribe(this, "topic1");
sync_ = std::make_shared>(sub1_, sub2_, 10);
sync_->registerCallback(std::bind(&MinimalSubscriber::topic_callback, this, _1, _2));
}
private:
void topic_callback(const sensor_msgs::msg::Image::ConstSharedPtr msg1,
const sensor_msgs::msg::Image::ConstSharedPtr msg2) const
{
int c = 0;
unsigned char buffer[8] = {0};
c = (msg1->height) * (msg2->height);
// std::cout << c << ","
// << msg1->height << ","
// << msg2->height << std::endl;
if (c != 0)
{
buffer[0] = 0x01;
buffer[1] = 0x05;
buffer[2] = 0x00;
buffer[3] = 0x02;
buffer[4] = 0x00;
buffer[5] = 0x00;
buffer[6] = 0x6C;
buffer[7] = 0x0A;
}
else
{
buffer[0] = 0x01;
buffer[1] = 0x05;
buffer[2] = 0x00;
buffer[3] = 0x02;
buffer[4] = 0xff;
buffer[5] = 0x00;
buffer[6] = 0x2D;
buffer[7] = 0xFA;
}
// RCLCPP_INFO(get_logger(), "结果:%d", c);
for (int i = 0; i < 8; i++)
{
std::cout << std::hex << (buffer[i] &0xff)<< " ";
}
std::cout< sub1_;
message_filters::Subscriber sub2_;
std::shared_ptr> sync_;
};
int main(int argc, char *argv[])
{
rclcpp::init(argc, argv);
ros_ser.setPort("/dev/ttyUSB0");
ros_ser.setBaudrate(9600);
serial::Timeout to =serial::Timeout::simpleTimeout(1000);
ros_ser.setTimeout(to);
try
{
ros_ser.open();
}
catch(serial::IOException &e)
{
std::cout<<"unable to open"<());
rclcpp::shutdown();
ros_ser.close();
return 0;
}
在cmakelist中添加代码中的依赖,同时给三个节点定义可执行文件。
添加依赖库
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(message_filters REQUIRED)
find_package(serial REQUIRED)
添加节点说明
add_executable(talker src/talker.cpp)
ament_target_dependencies(talker rclcpp sensor_msgs)
add_executable(talker1 src/talker1.cpp)
ament_target_dependencies(talker1 rclcpp sensor_msgs)
add_executable(lis src/lis.cpp)
ament_target_dependencies(lis rclcpp message_filters serial sensor_msgs)
同样,在package文件中添加依赖说明
ament_cmake
rclcpp
sensor_msgs
message_filters
serial
(未完待续)
完成以上内容后编译一下功能包
cd ~/ros2
colcon build --packages-select demo
(未完待续)
(未完待续)
1、ROS2 Humble如何使用串口驱动?(Serial)_腾腾任天真的博客-CSDN博客
(未完待续)