Ubuntu22.04下ROS2 Humble串口通信

1、安装准备

1.1安装ros2-for-serial-driver

sudo apt install ros-humble-serial-driver

1.2安装ch340驱动

Linux-ubuntu22.04串口驱动安装(CH34X)

1.3安装串口库依赖

ROS2 Humble 串口驱动依赖

1.4串口调试工具安装

sudo apt-get install cutecom

 打开调试工具

sudo cutecom

 打开界面如下

 可以在setting部分进行串口参数的配置

2、上位机端代码

2.1demo需求:

1、接收两个topic;

2、根据topic内容进行逻辑判断;

3、根据判断结果,发送16进制的8个byte的报文到设备;

在正式编写代码之前,首先先建立一下ros2的工作空间和工作包

mkdir -p ~/ros_ws/src
cd ~/ros_ws/src
ros2 pkg create --build-type ament_cmake demo

2.2编写发布者节点

2.2.1编写talker节点

cd ~/ros_ws/src/demo/src
touch talker.cpp

之后编写代码,talker节点会根据键盘的指令输入0或者1

#include <chrono>
#include <functional>
#include <memory>
#include <string>
#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<sensor_msgs::msg::Image>("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<sensor_msgs::msg::Image>::SharedPtr publisher_;
  size_t count_;
};
 
int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalPublisher>());
  rclcpp::shutdown();
  return 0;
}

2.2.2编写talker1节点

talker1会持续发送数字4

#include <chrono>
#include <functional>
#include <memory>
#include <string>
#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<sensor_msgs::msg::Image>("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<sensor_msgs::msg::Image>::SharedPtr publisher_;
  size_t count_;
};
 
int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinimalPublisher>());
  rclcpp::shutdown();
  return 0;
}

两个发布节点编写完毕

2.3编写接收者节点

首先需要接受两个节点的话题,并作逻辑处理,之后使用serial库文件的函数进行数据的发送,目前我们的设备可以通过hex数据包显示两种不同报文,发送报文:

第一种 0xFF、0x05、0x00、0x02、0x00、0x01、0x6A、0x6A、0x6A、0xFE,其中0xFF为包头,0xFE为包尾。

第二种0xFF、0x05、0x00、 0x02、 0xff、0x00、0x2B、0x6B、0x6C、0xFE,其中0xFF为包头,0xFE为包尾。
建立可执行文件

cd ~/ros_ws/src/demo/src
touch lis.cpp

以下是具体代码

#include <functional>
#include <memory>
#include <string>
#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<message_filters::TimeSynchronizer<sensor_msgs::msg::Image, sensor_msgs::msg::Image>>(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[10] = {0};
    c = (msg1->height) * (msg2->height);
    // std::cout <<  c << ","
    //           <<  msg1->height << ","
    //           <<  msg2->height << std::endl;
    if (c != 0)
    {
      buffer[0] = 0xFF;
      buffer[1] = 0x05;
      buffer[2] = 0x00;
      buffer[3] = 0x02;
      buffer[4] = 0x00;
      buffer[5] = 0x01;
      buffer[6] = 0x6A;
      buffer[7] = 0x6A;
      buffer[8] = 0x6A;
      buffer[9] = 0xFE;
    }
    else
    {
      buffer[0] = 0xFF;
      buffer[1] = 0x05;
      buffer[2] = 0x00;
      buffer[3] = 0x02;
      buffer[4] = 0xff;
      buffer[5] = 0x00;
      buffer[6] = 0x2B;
      buffer[7] = 0x6B;
      buffer[8] = 0x6C;
      buffer[9] = 0xFE;
    }
    // RCLCPP_INFO(get_logger(), "结果:%d", c);
    for (int i = 0; i < 10; i++)
    {
      std::cout << std::hex << (buffer[i] &0xff)<< " ";
    }
    std::cout<<std::endl;
    ros_ser.write(buffer,10);
  }
  message_filters::Subscriber<sensor_msgs::msg::Image> sub1_;
  message_filters::Subscriber<sensor_msgs::msg::Image> sub2_;
  std::shared_ptr<message_filters::TimeSynchronizer<sensor_msgs::msg::Image, sensor_msgs::msg::Image>> sync_;
};
 
int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  ros_ser.setPort("/dev/ttyUSB0");
  //ros_ser.BaudRate(9600);
  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"<<std::endl;
    return -1;
  }
  if(ros_ser.isOpen())
  {
    std::cout<<"open"<<std::endl;
  }
  else
  {
    return -1;
  }
 
  rclcpp::spin(std::make_shared<MinimalSubscriber>());
  rclcpp::shutdown();
  ros_ser.close();
  return 0;
}

3、下位端开发代码

下位机采用最小开发板

3.1接线图

3.2下位机代码

链接:https://pan.baidu.com/s/1IyXGR2hXfNVme_wgcwpGSQ?pwd=RMSR 提取码:RMSR

4、代码效果展示

使用方法

source install/setup.bash
ros2 run demo talker_node
ros2 run demo talker1_node
sudo chmod 777 /dev/ttyUSB0
ros2 run demo lis_node

4.1报文一

上位机端:

下位机端: 

4.1报文二

上位机端:

 下位机端:

5、可能遇到的问题

5.1程序编译无误,但端口无法打开

 解决方法:

1)输入命令

查看是否存在串口,或检查串口是否被占用。

ls -l /dev/ttyUSB0

 2)存在空闲的USB口,请检查/dev/ttyUSB0的权限,放开所有权限。

sudo chmod 777 /dev/ttyUSB0

5.2 error while loading shared libraries错误解决

Linux中运行代码时,找不到libserial.so动态链接库。

        出现这个问题时,常常是自己写的.so文件,代码可以编译成功,但是运行的话会出现error while loading shared libraries错误。原因是,Linux 运行的时候,共享库的寻找和加载是由 /lib/ld.so 实现的。默认配置下,ld.so 在标准路经(/) 中寻找应用程序用到的共享库。

        一般来说,使用make install会将自己编译的共享库放在在非标准路经中,比如/usr/local/lib中,而不是标准的动态库路径(/usr/lib)。此次需要修改配置,将*.so的路径写入配置中。

        解决方法有两个:

1)临时方案:

(重新打开terminal后失效)在Terminal中输入以下命令

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

2)长期方案:

(a)打开 ld.so.conf 文件

sudo gedit /etc/ld.so.conf

(b)在下面加入非标准的动态共享库路径:一般为/src/local/lib。 保存ld.so.conf 文件

(c)  记得执行ldconfig一下,添加的文件夹内容才能在程序运行时被找到。

sudo ldconfig

5.3部分新版本Ubuntu需要签名的问题Key was rejected by service

参考:解决Ubuntu22.04.1上安装ch34x串口驱动报 Key was rejected by service 需要签名的问题

5.4Brltty 导致 USB 转串口连接失败

参考:ubuntu22.04的 brltty 导致 USB 转串口连接失败

猜你喜欢

转载自blog.csdn.net/qq_50972633/article/details/132837550