news 2026/5/9 6:08:52

ROS2 Humble串口驱动实战:从源码编译到常见问题解决

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ROS2 Humble串口驱动实战:从源码编译到常见问题解决

1. ROS2 Humble串口驱动概述

在机器人开发中,串口通信是最基础也最常用的硬件交互方式之一。ROS2 Humble作为当前LTS版本,虽然功能强大,但官方并未内置串口驱动支持,这给开发者带来了一些挑战。我刚开始接触ROS2串口开发时,也踩过不少坑,比如动态库加载失败、权限不足等问题。

串口驱动本质上是一个跨平台的C++库,它封装了底层操作系统对串口设备的操作接口。在Linux系统中,串口设备通常以/dev/ttyUSB*/dev/ttyACM*形式存在。ROS2通过串口驱动可以与各类硬件设备通信,比如STM32控制器、传感器模块等。

与ROS1相比,ROS2的串口开发有几个显著变化:

  • 取消了rosserial包,需要手动集成串口库
  • 依赖管理更严格,需要正确处理ament_cmake构建系统
  • 动态库路径处理方式不同,容易引发error while loading shared libraries错误

2. 环境准备与依赖安装

2.1 系统要求

推荐使用Ubuntu 22.04 LTS系统,这是ROS2 Humble的官方支持平台。我测试过在Ubuntu 20.04上也能运行,但需要额外处理一些兼容性问题。

关键依赖包包括:

sudo apt install build-essential cmake libasio-dev libtinyxml2-dev \ libssl-dev python3-colcon-common-extensions

2.2 串口工具安装

调试串口时,这些工具非常有用:

sudo apt install minicom screen # 查看串口设备 ls /dev/ttyUSB* # 查看串口详细信息 udevadm info --query=all --name=/dev/ttyUSB0

2.3 创建工作空间

建议为串口项目创建独立的工作空间:

mkdir -p ~/serial_ws/src cd ~/serial_ws colcon build

3. 串口驱动源码编译

3.1 获取源码

推荐使用经过ROS2 Humble测试的fork版本:

cd ~/serial_ws/src git clone https://github.com/ZhaoXiangBox/serial.git

原始仓库虽然功能完整,但在ROS2环境下需要额外配置:

git clone https://github.com/wjwwood/serial.git

3.2 编译配置

使用CMake进行编译时,这几个参数很关键:

cd serial mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_TESTING=OFF

3.3 安装到系统

建议安装到/usr/local目录:

sudo make install sudo ldconfig

如果只想在当前用户下使用:

make install DESTDIR=~/local_install export LD_LIBRARY_PATH=~/local_install/usr/local/lib:$LD_LIBRARY_PATH

4. 常见问题解决方案

4.1 权限问题处理

最常见的错误就是串口设备权限不足:

# 查看设备权限 ls -l /dev/ttyUSB0 # 临时解决方案(重启失效) sudo chmod 777 /dev/ttyUSB0

永久解决方案是创建udev规则:

echo 'KERNEL=="ttyUSB*", MODE="0666"' | sudo tee /etc/udev/rules.d/50-ros2-serial.rules sudo udevadm control --reload sudo udevadm trigger

4.2 动态库加载失败

编译成功后运行时可能出现:

error while loading shared libraries: libserial.so: cannot open shared object file

解决方案有两种:

  1. 临时方案(当前终端有效):
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
  1. 永久方案:
sudo sh -c "echo '/usr/local/lib' >> /etc/ld.so.conf.d/serial.conf" sudo ldconfig

4.3 串口无法打开

即使编译通过,有时也会遇到串口无法打开的情况。首先检查:

# 查看串口是否存在 ls /dev/tty* # 检查是否被占用 lsof /dev/ttyUSB0

如果使用USB转串口设备,可能需要安装驱动。比如CH340/CH341芯片:

sudo apt install build-essential git clone https://github.com/juliagoda/CH341SER cd CH341SER make sudo make install sudo modprobe ch341

5. ROS2节点集成实践

5.1 创建功能包

cd ~/serial_ws/src ros2 pkg create --build-type ament_cmake serial_example \ --dependencies rclcpp serial

5.2 编写节点代码

创建src/serial_node.cpp

#include <rclcpp/rclcpp.hpp> #include <serial/serial.h> class SerialNode : public rclcpp::Node { public: SerialNode() : Node("serial_node") { try { ser.setPort("/dev/ttyUSB0"); ser.setBaudrate(115200); serial::Timeout to = serial::Timeout::simpleTimeout(1000); ser.setTimeout(to); ser.open(); } catch (serial::IOException& e) { RCLCPP_ERROR(this->get_logger(), "无法打开串口: %s", e.what()); } timer_ = this->create_wall_timer( std::chrono::milliseconds(100), std::bind(&SerialNode::timer_callback, this)); } private: void timer_callback() { if(ser.isOpen()) { std::string data = "Hello from ROS2\n"; ser.write(data); if(ser.available()) { std::string result = ser.read(ser.available()); RCLCPP_INFO(this->get_logger(), "收到: %s", result.c_str()); } } } serial::Serial ser; rclcpp::TimerBase::SharedPtr timer_; }; int main(int argc, char** argv) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<SerialNode>()); rclcpp::shutdown(); return 0; }

5.3 修改CMakeLists.txt

CMakeLists.txt中添加:

add_executable(serial_node src/serial_node.cpp) target_include_directories(serial_node PRIVATE ${serial_INCLUDE_DIRS} ) target_link_libraries(serial_node ${rclcpp_LIBRARIES} serial ) install(TARGETS serial_node DESTINATION lib/${PROJECT_NAME} )

5.4 编译与运行

cd ~/serial_ws colcon build --packages-select serial_example source install/setup.bash ros2 run serial_example serial_node

6. 高级配置与优化

6.1 参数化配置

使用ROS2参数系统动态配置串口:

// 在构造函数中添加 this->declare_parameter<std::string>("port", "/dev/ttyUSB0"); this->declare_parameter<int>("baudrate", 115200); ser.setPort(this->get_parameter("port").as_string()); ser.setBaudrate(this->get_parameter("baudrate").as_int());

6.2 多线程处理

对于高速串口通信,建议使用独立线程:

#include <thread> void read_thread() { while(rclcpp::ok() && ser.isOpen()) { if(ser.available()) { std::string result = ser.read(ser.available()); RCLCPP_INFO(this->get_logger(), "收到: %s", result.c_str()); } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } // 在构造函数中启动线程 std::thread(&SerialNode::read_thread, this).detach();

6.3 性能优化技巧

  1. 调整缓冲区大小:
ser.setBytesize(serial::eightbits); ser.setParity(serial::parity_none); ser.setStopbits(serial::stopbits_one);
  1. 使用硬件流控制(如果需要):
ser.setFlowcontrol(serial::flowcontrol_hardware);
  1. 启用RTS/CTS:
ser.setRTS(true); ser.setCTS(true);

7. 实际项目经验分享

在机器人项目中,我通常会封装一个更健壮的串口类。以下是几个关键点:

  1. 错误重试机制:当串口断开时自动尝试重连
void check_connection() { if(!ser.isOpen()) { try { ser.open(); RCLCPP_WARN(this->get_logger(), "串口重新连接成功"); } catch (...) { RCLCPP_ERROR(this->get_logger(), "串口重连失败"); } } }
  1. 数据协议处理:使用帧头+长度+校验位格式
bool validate_packet(const std::string& data) { if(data.length() < 4) return false; uint8_t checksum = 0; for(size_t i=0; i<data.length()-1; ++i) { checksum ^= data[i]; } return checksum == data.back(); }
  1. 超时处理:设置合理的读写超时
serial::Timeout to = serial::Timeout::simpleTimeout(500); ser.setTimeout(to);
  1. 日志记录:重要操作记录日志
RCLCPP_DEBUG(this->get_logger(), "发送数据: %s", to_hex_string(data).c_str());

遇到最棘手的问题是USB转串口设备在长时间运行后突然断开。解决方案是增加心跳检测机制,定期检查连接状态,并在异常时重置端口。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/6 4:14:18

AI绘画新体验:Z-Image Turbo一键生成惊艳作品

AI绘画新体验&#xff1a;Z-Image Turbo一键生成惊艳作品 1. 开箱即用的极速画板&#xff1a;为什么这次真的不一样&#xff1f; 你有没有过这样的经历&#xff1a; 花半小时调参数、等显存不爆、防黑图、修提示词&#xff0c;最后生成一张图——结果边缘发灰、手长了六根、天…

作者头像 李华
网站建设 2026/5/6 4:12:24

EagleEye部署教程:Kubernetes集群中弹性扩缩容EagleEye推理服务

EagleEye部署教程&#xff1a;Kubernetes集群中弹性扩缩容EagleEye推理服务 1. 为什么需要在K8s里跑EagleEye&#xff1f; 你有没有遇到过这样的情况&#xff1a;白天监控摄像头突然涌入大量视频流&#xff0c;检测请求暴增三倍&#xff0c;GPU显存直接飙到98%&#xff0c;服…

作者头像 李华
网站建设 2026/4/30 23:40:34

translategemma-4b-it效果实测:不同光照/角度/分辨率下图文翻译一致性

translategemma-4b-it效果实测&#xff1a;不同光照/角度/分辨率下图文翻译一致性 你有没有遇到过这样的情况&#xff1a;拍了一张菜单、路标或说明书照片&#xff0c;想用AI直接翻译&#xff0c;结果光线一暗、手机歪一点、或者图片糊了点&#xff0c;翻译就出错&#xff1f;…

作者头像 李华
网站建设 2026/5/9 4:39:53

mPLUG视觉问答工具从零开始:Ubuntu/CentOS本地环境部署步骤详解

mPLUG视觉问答工具从零开始&#xff1a;Ubuntu/CentOS本地环境部署步骤详解 1. 为什么你需要一个本地化的视觉问答工具&#xff1f; 你有没有遇到过这样的场景&#xff1a;手头有一张产品实拍图&#xff0c;想快速知道图中物品的品牌、数量或摆放关系&#xff0c;却要反复上传…

作者头像 李华
网站建设 2026/5/7 18:15:46

Phi-3-mini-4k-instruct实测:轻量级AI写作助手一键体验

Phi-3-mini-4k-instruct实测&#xff1a;轻量级AI写作助手一键体验 1. 为什么需要一个“轻量级”写作助手&#xff1f; 你有没有过这样的经历&#xff1a;想快速写一封工作邮件&#xff0c;却在开头卡了五分钟&#xff1b;要给产品写宣传文案&#xff0c;翻来覆去改了七版还是…

作者头像 李华
网站建设 2026/4/30 18:39:19

企业级失物招领平台管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

摘要 随着社会信息化程度的不断提高&#xff0c;失物招领管理在公共场所、校园及企业环境中显得尤为重要。传统的失物招领方式依赖人工登记和线下公告&#xff0c;效率低下且信息传递范围有限&#xff0c;容易导致物品长期滞留或无法匹配失主。企业级失物招领平台管理系统通过数…

作者头像 李华