鱼香ROS社区
    • 版块
    • 最新
    • 未解决
    • 已解决
    • 群组
    • 注册
    • 登录
    紧急通知:禁止一切关于政治&VPN翻墙等话题,发现相关帖子会立马删除封号
    提问前必看的发帖注意事项: 社区问答规则(小鱼个人)更新 | 高质量帖子发布指南

    serial串口通信

    已定时 已固定 已锁定 已移动
    ROS 2相关问题
    串口 通信
    5
    15
    2.9k
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • 小鱼小
      小鱼 技术大佬 @凌云
      最后由 编辑

      @凌云这个你问对人啦,小鱼前几天才做了一个开源库,支持在ROS2下几行代码使用串口。

      在写FishBot的SDK时,小鱼打算以多种方式进行数据的通信的,包括串口、UDP、TCP等,所以就对通信模块进行了封装,实现简单的更换配置,完成协议的切换。

      因为前段时间总有小伙伴问如何在ROS2中调用串口,就想着要不把这部分代码抽出来给大家,二来后续的更新和维护可以从FishBot中抽离出来,方便更多的小伙伴一起Work。同时小鱼顺手写了一个ROS2的例程,当然还有g++和CMake版本的使用样例代码。

      开源地址:https://github.com/fishros/fish_protocol

      FishProtocol

      FishProtocol是一个方便的C++多协议(串口/UDP/TCP)通信库。

      FishProtocol是从FishBot的Driver中抽离出的,采用boost库作为核心进行了二次封装,可以简单快速的通过几行代码建立串口/UDP等通信。随着FishBot的不断完善,该库也将不断的更新完善,后续将同时支持对多端进行同时连接,实现多机控制等功能。

      同时该库也可以在ROS2中使用,工程中提供有相关例程,见examples文件夹。

      1.快速安装

      sudo apt install libboost-dev
      git clone https://gh.api.99988866.xyz/https://github.com/fishros/fish_protocol.git 
      cd fish_protocol && mkdir build  && cd build
      cmake .. && sudo make install # 将安装到系统库
      

      2.快速使用/串口通信

      fish_protocol::ProtocolConfig proto_config;
      proto_config.protocol_type_ = PROTOCOL_TYPE::SERIAL;
      proto_config.serial_baut_ = 115200;
      proto_config.serial_address_ = "/dev/ttyS12";
      
      // 初始化
      auto protocol = GetProtocolByConfig(proto_config);
      
      // 发送数据
      protocol->ProtocolSendRawData("Hello FishBot!");
      
      // 接收数据
      protocol->SetDataRecvCallback([](const std::string& data) -> void {
          std::cout<<"recv"<<data<<std:endl;
      });
      
      // 销毁
      protocol->ProtocolDestory();
      

      3.快速上手/UDPServer通信

      fish_protocol::ProtocolConfig proto_config;
      proto_config.protocol_type_ = PROTOCOL_TYPE::UDP_SERVER;
      proto_config.udp_server_ip_ = "0.0.0.0";
      proto_config.udp_server_port_ = 3474;
      
      // 初始化
      auto protocol = GetProtocolByConfig(proto_config);
      
      // 发送数据
      protocol->ProtocolSendRawData("Hello FishBot!");
      
      // 接收数据
      protocol->SetDataRecvCallback([](const std::string& data) -> void {
          std::cout<<"recv"<<data<<std:endl;
      });
      
      // 销毁
      protocol->ProtocolDestory();
      

      4.在ROS2中使用-串口通信

      #include "fish_protocol/fish_protocol.h"
      #include "rclcpp/rclcpp.hpp"
      
      int main(int argc, char** argv) {
        /* 初始化rclcpp  */
        rclcpp::init(argc, argv);
        /*产生一个node_01的节点*/
        auto node = std::make_shared<rclcpp::Node>("example_fish_protocol");
        // 打印一句自我介绍
        RCLCPP_INFO(node->get_logger(), "example_fish_protocol节点已经启动.");
      
        fish_protocol::ProtocolConfig proto_config;
        proto_config.protocol_type_ = fish_protocol::PROTOCOL_TYPE::SERIAL;
        proto_config.serial_baut_ = 115200;
        proto_config.serial_address_ = "/dev/ttyS12";
        // 初始化
        auto protocol = GetProtocolByConfig(proto_config);
        // 发送数据
        protocol->ProtocolSendRawData("Hello FishBot!");
        // 接收数据
        protocol->SetDataRecvCallback([](const std::string& data) -> void {
          std::cout << "recv" << data << std::endl;
        });
        // 销毁
        protocol->ProtocolDestory();
      
        /* 运行节点,并检测退出信号 Ctrl+C*/
        rclcpp::spin(node);
        /* 停止运行 */
        rclcpp::shutdown();
        return 0;
      }
      

      新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

      毛哥成山轮胎机油保养毛 32904162883 2 条回复 最后回复 回复 引用 0
      • 凌云凌
        凌云
        最后由 编辑

        看起来不错,我试试。谢谢。

        1 条回复 最后回复 回复 引用 0
        • 凌云凌
          凌云
          最后由 凌云 编辑

          谢谢你的轮子!
          但是我想要通过串口发送字节数组,而非字符串,有相关的接口函数可用吗?
          另外,接收回调函数如何写成独立函数的形式?

          小鱼小 1 条回复 最后回复 回复 引用 0
          • 小鱼小
            小鱼 技术大佬 @凌云
            最后由 编辑

            @凌云

            1. 字节数组和字符串可以直接互转的
            2. 可以直接使用std::bind将普通函数变为回调函数形式

            新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

            凌云凌 1 条回复 最后回复 回复 引用 0
            • 凌云凌
              凌云 @小鱼
              最后由 编辑

              @小鱼 thanks!

              1 条回复 最后回复 回复 引用 0
              • 毛哥成山轮胎机油保养毛
                毛哥成山轮胎机油保养 活跃VIP @小鱼
                最后由 编辑

                @小鱼 最近入手了一个JY_ 95t imu ,只找到了python的程序,没有c++的,这个imu在接收数据以前,需要发送一段16进制的数据:0xA4 0x03 0x08 0x23 0xD2配置imu 我看了你的程序,protocol->ProtocolSendRawData("Hello FishBot!"); 只能发送字符串,怎样才能发送16进制的数据呢?这是你的示例程序返回的结果:open with/dev/ttyUSB0
                send14
                start send******
                0x48 0x65 0x6C 0x6C 0x6F 0x20 0x46 0x69 0x73 0x68 0x42 0x6F 0x74 0x21

                小鱼小 1 条回复 最后回复 回复 引用 0
                • 小鱼小
                  小鱼 技术大佬 @毛哥成山轮胎机油保养
                  最后由 编辑

                  @毛哥成山轮胎机油保养 一个字符串刚好是一个byte,8个bit。
                  所以bytes可以和string可以互相转换


                  当你想要在 C++ 中将 std::string 和字节数组之间进行转换时,可以使用 reinterpret_cast 进行转换。下面是一个示例代码,展示了如何在两者之间进行互相转换:

                  #include <iostream>
                  #include <string>
                  #include <vector>
                  
                  // 将字节数组转换为 std::string
                  std::string ByteArrayToString(const std::vector<unsigned char>& byteArray) {
                      return std::string(reinterpret_cast<const char*>(byteArray.data()), byteArray.size());
                  }
                  
                  // 将 std::string 转换为字节数组
                  std::vector<unsigned char> StringToByteArray(const std::string& str) {
                      std::vector<unsigned char> byteArray(str.begin(), str.end());
                      return byteArray;
                  }
                  
                  int main() {
                      // 示例:将字节数组转换为 std::string
                      std::vector<unsigned char> byteArray = {72, 101, 108, 108, 111, 33};
                      std::string str = ByteArrayToString(byteArray);
                      std::cout << "String: " << str << std::endl;
                  
                      // 示例:将 std::string 转换为字节数组
                      std::string message = "Hello, world!";
                      std::vector<unsigned char> convertedArray = StringToByteArray(message);
                      std::cout << "Byte Array: ";
                      for (unsigned char byte : convertedArray) {
                          std::cout << static_cast<int>(byte) << " ";
                      }
                      std::cout << std::endl;
                  
                      return 0;
                  }
                  

                  上述代码中,ByteArrayToString 函数接收一个字节数组(std::vector<unsigned char>),并使用 reinterpret_cast 将其转换为 const char*,然后通过构造函数将其转换为 std::string。

                  StringToByteArray 函数接收一个 std::string,并通过使用迭代器将其转换为 std::vector<unsigned char>。

                  请注意,这种方法假设字节数组中的每个字节都对应一个有效的字符,且字符编码没有发生变化。在某些情况下,这种转换可能不是无损的,因此在实际应用中要小心处理。

                  新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                  毛哥成山轮胎机油保养毛 1 条回复 最后回复 回复 引用 0
                  • 毛哥成山轮胎机油保养毛
                    毛哥成山轮胎机油保养 活跃VIP @小鱼
                    最后由 编辑

                    @小鱼 在 serial串口通信 中说:

                    // 示例:将 std::string 转换为字节数组
                    std::string message = "Hello, world!";
                    std::vector<unsigned char> convertedArray = StringToByteArray(message);
                    std::cout << "Byte Array: ";
                    for (unsigned char byte : convertedArray) {
                    std::cout << static_cast<int>(byte) << " ";
                    }
                    std::cout << std::endl;

                    #include "fish_protocol/fish_protocol.h"
                    //#include <iostream>
                    //#include <string>
                    //#include <vector>

                    // 将字节数组转换为 std::string
                    std::string ByteArrayToString(const std::vector<unsigned char>& byteArray) {
                    return std::string(reinterpret_cast<const char*>(byteArray.data()), byteArray.size());
                    }

                    // 将 std::string 转换为字节数组
                    std::vector<unsigned char> StringToByteArray(const std::string& str) {
                    std::vector<unsigned char> byteArray(str.begin(), str.end());
                    return byteArray;
                    }

                    int main(int argc, char const* argv[]) {
                    fish_protocol::ProtocolConfig proto_config;
                    proto_config.protocol_type_ = fish_protocol::PROTOCOL_TYPE::SERIAL;
                    proto_config.serial_baut_ = 115200;
                    proto_config.serial_address_ = "/dev/ttyUSB0";

                    // 初始化
                    auto protocol = GetProtocolByConfig(proto_config);

                    //send_data = [0xA4,0x03,0x08,0x23,0xD2]
                    // 将字节数组转换为 std::string
                    std::vector<unsigned char> byteArray = {0xA4,0x03,0x08,0x23,0xD2};
                    std::string str = ByteArrayToString(byteArray);

                    // 发送数据
                    protocol->ProtocolSendRawData(str);

                    // 接收数据
                    protocol->SetDataRecvCallback([](const std::string& data) -> void {

                    //将接收到的 std::string & data转换为字节数组
                    std::vector<unsigned char> convertedArray = StringToByteArray(data);
                    std::cout << "Byte Array: ";
                    for (unsigned char byte : convertedArray) {
                        std::cout << static_cast<int>(byte) << " ";
                    }
                    std::cout << std::endl;
                    

                    });

                    // 销毁
                    protocol->ProtocolDestory();
                    return 0;
                    }

                    可以正常发送16进制数据了,可是为什么没有读到imu发回的数据呢?
                    open with/dev/ttyUSB0
                    send5
                    start send******
                    0xA4 0x03 0x08 0x23 0xD2
                    end send******

                    小鱼小 1 条回复 最后回复 回复 引用 0
                    • 小鱼小
                      小鱼 技术大佬 @毛哥成山轮胎机油保养
                      最后由 编辑

                      @毛哥成山轮胎机油保养 在 serial串口通信 中说:

                      // 销毁
                      protocol->ProtocolDestory();

                      这句之前加上个delay,还没来得及接受到数据就exit了

                      新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                      8679758198 2 条回复 最后回复 回复 引用 0
                      • 8679758198
                        圆梦 @小鱼
                        最后由 编辑

                        @小鱼 那我想发送一个uint8或者float型的数据该怎么办?

                        1 条回复 最后回复 回复 引用 0
                        • 8679758198
                          圆梦 @小鱼
                          最后由 编辑

                          @小鱼 他只能发送一种类型?

                          小鱼小 1 条回复 最后回复 回复 引用 0
                          • 小鱼小
                            小鱼 技术大佬 @867975819
                            最后由 编辑

                            @867975819 bytes可以代表一切类型

                            新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                            1 条回复 最后回复 回复 引用 0
                            • 32904162883
                              鲜橙多 @小鱼
                              最后由 编辑

                              @小鱼 41af58e1-ce07-4033-88dc-37071021ba29-image.png 为什么在容器中安装,执行cpp文件一直显示无法找到对应的package呢

                              小鱼小 1 条回复 最后回复 回复 引用 0
                              • 小鱼小
                                小鱼 技术大佬 @3290416288
                                最后由 编辑

                                @3290416288 只支持ROS2

                                新书配套视频:https://www.bilibili.com/video/BV1GW42197Ck/

                                1 条回复 最后回复 回复 引用 0
                                • 第一个帖子
                                  最后一个帖子
                                皖ICP备16016415号-7
                                Powered by NodeBB | 鱼香ROS