树莓派+激光雷达实现DWA动态路径规划闭环系统
2026/9/17 1:22:27 网站建设 项目流程

1. 项目概述:这不是玩具车,而是一套可复现、可调试、可进阶的移动机器人路径规划闭环系统

“自动驾驶小车DIY:树莓派+激光雷达实现DWA路径规划(从仿真到实车)”——这个标题里藏着三个关键层级:硬件载体(树莓派)感知核心(激光雷达)决策中枢(DWA算法)。它不是拼凑几个模块就跑起来的演示demo,而是一条从Gazebo仿真验证、ROS节点集成、传感器驱动适配、参数调优,最终落地到真实轮式底盘上完成动态避障与目标趋近的完整技术链。我带过六届本科生毕设,也帮三家公司做过AGV原型验证,最常看到的问题就是:学生用树莓派4B接了个TFMini激光测距模块,跑个A*算法在空旷走廊里绕一圈,就敢叫“自动驾驶小车”。但真正的DWA(Dynamic Window Approach)路径规划,要求系统每秒至少处理10帧以上激光扫描数据(即10Hz),在20ms内完成障碍物聚类、速度空间采样、轨迹评估与最优控制量输出,并实时反馈给底层电机控制器。这背后是ROS的实时性约束、树莓派的CPU调度瓶颈、激光雷达驱动的中断响应延迟、以及DWA参数对物理底盘动力学的强耦合——任何一个环节掉链子,小车就会原地打转、撞墙、或突然急停。所以这个项目真正解决的是:如何在资源受限的嵌入式平台(树莓派)上,构建一个具备工程鲁棒性的局部路径规划闭环,让小车在未知动态环境中,像人一样“边走边想”,而不是靠预设路径硬闯。适合两类人深度参考:一是需要交付高质量毕设/课程设计的本科生,尤其关注“鱼香ROS一键安装”这类实操痛点;二是刚入门ROS机器人开发的工程师,想跳过ROS2的复杂生态,用成熟稳定的ROS Noetic+Ubuntu 20.04快速验证算法逻辑。它不教你怎么写ROS基础教程,而是直接告诉你:当你的小车在Gazebo里跑得飞起,一上实车就抖动失联时,问题大概率出在/scan话题的timestamp同步、base_linklaser的TF坐标系偏移、或者DWA配置中max_vel_xacc_lim_x的物理匹配上。

2. 整体架构设计与技术选型逻辑:为什么非得是树莓派+激光雷达+ROS+DWA这条技术栈?

2.1 硬件平台:树莓派不是“便宜替代品”,而是嵌入式ROS部署的黄金平衡点

很多人问:为什么不用Jetson Nano?它GPU更强啊。我的实测结论是:对于纯DWA这类CPU密集型、无图像识别需求的局部规划任务,树莓派4B(4GB RAM)比Jetson Nano更稳、更省心、更易调试。Jetson Nano的CUDA加速在DWA里根本用不上——DWA核心是大量浮点向量运算和循环遍历,OpenMP多线程优化已足够,GPU反而因驱动兼容性问题导致ROS节点频繁崩溃。而树莓派4B的优势在于三点:第一,Ubuntu 20.04 LTS官方支持完善,内核版本5.4长期维护,所有ROS Noetic依赖包(如ros-noetic-navigation)都能一键apt install,不像某些ARM板需手动编译;第二,GPIO引脚定义清晰、文档齐全,驱动TB6612FNG电机驱动板时,用wiringpi库直接操作PWM引脚,误差控制在±0.5%以内,远超树莓派Pico的模拟PWM精度;第三,散热与功耗比极佳,连续运行8小时,CPU温度稳定在65℃(加装铝制散热片+静音风扇),而Jetson Nano满载时风扇噪音达45dB,且需额外供电管理。我曾用树莓派5试跑同一套DWA节点,结果因USB3.0控制器与RPLIDAR A3驱动冲突,导致/scan数据丢帧率达12%,最终退回4B。所以选型逻辑很朴素:不追求参数峰值,而追求“能7×24小时稳定输出10Hz激光数据流”的工程确定性。树莓派4B就是那个经过千人验证的“稳态解”。

2.2 感知层:激光雷达不是越贵越好,RPLIDAR A3是实车DWA的“呼吸器官”

DWA算法的输入是二维激光扫描点云(sensor_msgs/LaserScan),它的质量直接决定避障成败。我对比过四款主流雷达:思岚A1(360°/12m/4kHz)、速腾聚创RS-LiDAR-M1(128线/200m)、北醒CE30(TOF/单线)、RPLIDAR A3(360°/25m/16kHz)。结论很明确:RPLIDAR A3是树莓派实车项目的唯一合理选择。原因有三:其一,数据吞吐量匹配。A3标称16kHz扫描频率,实际在树莓派4B上通过USB2.0(480Mbps)稳定输出10Hz全角度扫描(每帧2200+点),而A1仅8kHz,在动态场景下点云稀疏,DWA评估轨迹时容易漏检移动障碍物;其二,驱动成熟度碾压rplidar_ros包在ROS Noetic中开箱即用,roslaunch rplidar_ros rplidar.launch/scan话题延迟<15ms,而M1需定制ROS2驱动,CE30的TOF原理在强光下信噪比骤降;其三,成本与可靠性平衡。A3单价约¥599,寿命>10000小时,我实验室两台A3连续运行18个月零故障,而某国产低价雷达(¥299)在潮湿环境运行3周后出现电机卡顿,导致扫描角度偏移±3°,DWA直接失效。这里有个关键细节:A3必须配原装USB线(屏蔽层双绞),普通USB线会导致高频干扰,/scan数据中出现大量inf值——这不是软件bug,是电磁兼容问题。我在树莓派USB口并联100nF陶瓷电容后,丢点率从8%降至0.3%。所以选雷达,本质是选“能持续提供干净、低延迟、高密度点云”的物理传感器,而非参数表上的数字。

2.3 软件栈:ROS Noetic不是“过时选择”,而是DWA工业验证的基石

当前网络热词里“ROS2 Humble”“Micro-ROS”声量很大,但做DWA实车,我坚持用ROS Noetic(Ubuntu 20.04)。理由很实在:move_base导航栈中的dwa_local_planner是经过十年以上AGV、扫地机器人量产验证的C++实现,其代码结构清晰、参数文档完备、社区问题库丰富。ROS2的nav2虽新,但dwb_controller(DWB即DWA的ROS2版)在树莓派上编译失败率高达37%(因依赖ament_cmakecolcon工具链冲突),且参数调试界面不如Noetic的rqt_reconfigure直观。更重要的是,所有经典DWA论文(Fox et al., 1997)的开源实现都基于ROS1,比如teb_local_planner的对比测试数据、dwa_planner的源码注释,全指向Noetic环境。所谓“鱼香ROS一键安装”,本质是封装了rosdep installcatkin_makesetup.bash等重复操作,但底层仍是Noetic的move_base框架。我统计过GitHub上star数超500的DWA相关仓库,92%明确标注“ROS Noetic compatible”。因此,技术选型不是追逐新潮,而是选择被最多真实机器人验证过的最小可行路径。你花三天搞定鱼香ROS安装,不如花一天理解dwa_local_plannercost_functions.cppfootprint_cost如何计算机器人轮廓与障碍物距离——后者才是DWA不撞墙的核心。

2.4 算法层:DWA不是“高级路径规划”,而是为轮式底盘量身定制的动态窗口法

很多人把DWA和A*、RRT混为一谈,这是根本性误解。A是全局规划器(global_planner),负责生成从起点到终点的粗略路径;DWA是局部规划器(local_planner),只管“接下来0.5秒怎么走”。它的数学本质是:在机器人当前速度(v, ω)构成的二维空间中,划定一个“动态窗口”(由最大加速度acc_lim_x/y/th约束),对窗口内每个(v, ω)采样,前向模拟0.5秒轨迹,计算该轨迹的三项代价:轨迹与全局路径的偏离度、轨迹末端与目标点的距离、轨迹最近点到障碍物的安全距离。最终选择总代价最低的(v, ω)作为本轮控制输出。这个过程每20ms执行一次,形成闭环。关键点在于:DWA不预测障碍物运动,只对当前激光帧做瞬时避障。所以它天然适合树莓派——无需SLAM建图,不依赖GPS,只要激光数据在线,就能工作。我曾用DWA让小车在办公室走廊自主避让突然冲出的同事,反应时间180ms(从激光扫描到电机响应),而A重规划需2.3秒。因此,DWA的价值不是“多智能”,而是“多可靠”:它把复杂的运动规划,压缩成一个可实时求解的优化问题,这才是嵌入式平台能扛住的算力负荷。

3. 核心模块拆解与实操要点:从Gazebo仿真到实车部署的七道关卡

3.1 Gazebo仿真环境搭建:先让小车在虚拟世界里“学会走路”

仿真不是摆设,它是暴露DWA参数缺陷的第一道筛子。我用turtlebot3_waffle_pi模型为基础,但做了三处关键改造:第一,替换激光雷达插件。原模型用gazebo_ros_laser,但其噪声模型固定,无法模拟实车A3的量化误差。我改用libgazebo_ros_gpu_laser.so,并在SDF文件中添加<noise><type>gaussian</type><mean>0.0</mean><stddev>0.01</stddev></noise>,使模拟点云每帧有±1cm随机偏移,逼真复现A3的测量不确定性;第二,增加动态障碍物。用gazebo_ros_pkgsspawn_model脚本,在仿真中随机生成以0.3m/s匀速横穿路径的Box模型,测试DWA的实时避让能力;第三,校准TF坐标系。在urdf中严格定义base_link(底盘中心)到laser(雷达中心)的偏移:<origin xyz="0 0 0.15" rpy="0 0 0"/>,Z轴偏移15cm对应A3安装高度,此值若错1cm,DWA计算的安全距离偏差达3.2cm,小车必撞墙。实操时,我用rvizTF面板实时监控base_linklaser的相对位姿,确保/tf话题中rotation四元数w=1.0,x=y=z=0.0。仿真启动命令不是简单roslaunch turtlebot3_gazebo turtlebot3_world.launch,而是:

roslaunch turtlebot3_gazebo turtlebot3_world.launch world_file:=$(rospack find turtlebot3_gazebo)/worlds/turtlebot3_house.world & roslaunch turtlebot3_gazebo turtlebot3_simulation.launch & roslaunch dwa_local_planner dwa_planner.launch

其中turtlebot3_house.world包含真实比例的门框、桌腿,用于测试DWA在狭窄空间的转向能力。仿真阶段必须达成两个指标:1)/cmd_vel输出频率稳定10Hz;2)小车在0.5m宽通道中能以0.2m/s匀速通过,无剧烈左右摇摆。若不达标,立即检查dwa_plannermin_vel_x(建议设为0.05)和sim_time(建议0.6-0.8s),而非怪硬件。

3.2 树莓派系统配置:绕过Ubuntu 20.04的“坑阵”

树莓派4B装Ubuntu 20.04桌面版(非Server版),因为ROS可视化工具(rviz,rqt)需GUI。但默认镜像有三大陷阱:第一,USB供电不足。A3雷达+USB摄像头同时接入时,树莓派会触发under-voltage警告,导致USB设备断连。解决方案:禁用vc4显卡驱动(sudo nano /boot/config.txt,添加dtoverlay=vc4-fkms-v3d改为#dtoverlay=vc4-fkms-v3d),改用fbturbo帧缓冲驱动,GPU功耗降40%;第二,时钟同步漂移。树莓派无RTC芯片,长时间运行后系统时间误差达5s/天,导致/scan/tf时间戳不匹配,move_base报错Transform failed。用systemd-timesyncd强制NTP同步:sudo timedatectl set-ntp true,并编辑/etc/systemd/timesyncd.conf,将NTP=行改为NTP=cn.pool.ntp.org;第三,swap分区拖慢ROS。默认100MB swap在内存满时引发磁盘IO风暴,roslaunch卡死。sudo dphys-swapfile swapoff && sudo nano /etc/dphys-swapfile,将CONF_SWAPSIZE=100改为CONF_SWAPSIZE=0,彻底禁用swap,靠4GB RAM硬扛。这些配置看似琐碎,但缺一不可——我见过太多人卡在/scan话题无数据,最后发现是USB供电问题,而非驱动没装。

3.3 RPLIDAR A3驱动与数据校验:让激光雷达“说真话”

rplidar_ros包安装后,roslaunch rplidar_ros rplidar.launch应输出[INFO] [xxx]: RPLIDAR running on: /dev/ttyUSB0。但此时需做三重校验:

  1. 物理连接校验:用ls -l /dev/ttyUSB*确认设备号,若显示/dev/ttyUSB1,则修改launch文件中<param name="port" value="/dev/ttyUSB1"/>
  2. 数据质量校验rostopic hz /scan应稳定在10Hz,rostopic echo /scan/range_min应为0.15(A3最小测距),range_max为25.0;
  3. 点云完整性校验rviz中添加LaserScan,Topic选/scan,若出现大片空白或inf值,立即执行sudo chmod a+rw /dev/ttyUSB0赋予读写权限,并检查USB线是否原装。
    最关键的一步是角度校准。A3出厂有±0.5°安装误差,需用rplidar_rosrplidar_node参数angle_compensate:=true开启自动补偿,但此功能依赖frame_id设为laser。若/tflaser坐标系未正确定义,补偿失效。我在robot_state_publisher的URDF中添加:
<joint name="laser_joint" type="fixed"> <parent link="base_link"/> <child link="laser"/> <origin xyz="0 0 0.15" rpy="0 0 0"/> </joint> <link name="laser"/>

然后roslaunch robot_state_publisher robot_state_publisher.launch,用tf_echo base_link laser验证偏移量。实测表明,角度误差每增加0.3°,DWA在1m距离的避障半径偏差达5.2cm——这解释了为何小车总在离墙0.3m处急停。

3.4 DWA参数精调:不是调参,而是匹配你的物理底盘

DWA的dwa_local_planner_params.yaml有27个参数,但核心只有6个,它们必须与你的电机、轮距、惯量物理匹配:

  • max_vel_x: 0.3→ 对应电机最大线速度(m/s),实测方法:rostopic pub /cmd_vel geometry_msgs/Twist "linear: {x: 0.3}",用激光测距仪测小车实际速度,若仅0.22m/s,则调至0.22;
  • acc_lim_x: 0.8→ 电机最大加速度(m/s²),计算公式:acc_lim_x = (max_vel_x)² / (2 * braking_distance),刹车距离取0.15m(实测急停距离),得0.8;
  • yaw_goal_tolerance: 0.05→ 角度容忍度(rad),对应3°,过大则转向不精准,过小则原地振荡;
  • xy_goal_tolerance: 0.1→ 位置容忍度(m),即到达目标点10cm内视为成功;
  • sim_time: 0.7→ 轨迹模拟时长(s),太短(<0.5)无法避开快速障碍物,太长(>1.0)计算延迟超限;
  • path_distance_bias: 32.0→ 路径贴合权重,值越大越紧贴全局路径,但易撞墙,建议从20开始逐步上调。
    调参口诀:先调max_vel_xacc_lim_x保安全,再调sim_timeyaw_goal_tolerance保流畅,最后微调path_distance_bias保精度。我用rqt_reconfigure实时调整,观察/cmd_velangular.z输出是否平滑——若出现±1.2rad/s的尖峰,说明yaw_goal_tolerance过小,需放大。

3.5 底层电机控制:让DWA的“想法”变成车轮的“动作”

DWA输出/cmd_vel(Twist消息),但树莓派不能直接驱动电机,需通过串口或PWM转换。我用TB6612FNG驱动板,接树莓派GPIO:

  • AIN1→GPIO17,AIN2→GPIO27,PWMA→GPIO18(硬件PWM0)
  • BIN1→GPIO22,BIN2→GPIO23,PWMB→GPIO13(硬件PWM1)
    关键在PID闭环控制/cmd_vellinear.x需转换为左右轮PWM占空比:
left_pwm = int(255 * (linear_x - angular_z * wheel_base/2) / max_vel_x) right_pwm = int(255 * (linear_x + angular_z * wheel_base/2) / max_vel_x)

其中wheel_base=0.26(轮距0.26m),max_vel_x=0.3。但开环控制会因电池电压下降导致速度衰减,故加入编码器反馈。我用霍尔传感器(1000线/转)接GPIO24/25,用pigpio库读取脉冲,计算实际速度,与/cmd_vel指令速度做PID差值,动态修正PWM。PID参数Kp=0.8, Ki=0.02, Kd=0.1经Ziegler-Nichols整定得出。实测表明,无PID时速度波动±15%,有PID后稳定在±2%。这步不可省——DWA假设输出速度能被精确执行,若底层失控,再好的规划也是空中楼阁。

3.6 TF坐标系统一:机器人世界的“语言翻译官”

ROS中所有传感器数据必须在统一坐标系下解读,TF(Transform)就是翻译官。本项目涉及四个关键坐标系:

  • map:全局地图原点,由SLAM或静态地图定义;
  • odom:里程计原点,随小车移动累积误差;
  • base_link:小车底盘中心,所有运动学计算基准;
  • laser:激光雷达中心,/scan数据的发布坐标系。
    必须保证map → odom → base_link → laser的TF链完整。常见错误:robot_state_publisher未加载URDF,导致base_linklaser缺失;或odometry节点未发布odom → base_link,导致move_base报错No transform from [base_link] to [map]。诊断命令:rosrun tf view_frames生成frames.pdf,检查是否有断链;rosrun tf tf_echo odom base_link看位移是否随运动变化。我强制要求:每次roslaunch后,首先进入rviz,添加TF显示,确认四色坐标系(红X绿Y蓝Z)全部可见且无抖动。TF是隐形的骨架,骨架歪了,整个系统就瘫痪。

3.7 实车动态避障测试:用真实场景“压力测试”DWA

仿真通过后,实车测试分三阶段:
第一阶段:静态环境。在空旷教室铺设0.5m×0.5m方格纸,用激光测距仪标定A3安装高度(15cm),运行roslaunch turtlebot3_navigation turtlebot3_navigation.launch,发布2D Nav Goal,观察小车是否沿直线匀速抵达,/cmd_vellinear.x波动<±0.02m/s;
第二阶段:窄道挑战。设置0.6m宽通道(两排课桌),要求小车以0.15m/s通过,DWA的inflation_radius必须≥0.25m(膨胀半径),否则擦碰桌腿;
第三阶段:动态干扰。一人持纸板以0.5m/s横向穿越路径,小车应在0.8m外开始减速,0.3m处完全停止,待纸板离开后1.2秒内恢复行驶。若急停距离>0.5m,调大acc_lim_x;若恢复延迟>2s,调小oscillation_reset_dist(振荡重置距离)。
终极检验:连续运行2小时,记录rostopic hz /scan/cmd_vel的丢帧率,合格线是<0.5%。我实验室的纪录是18小时无丢帧,靠的是前述所有环节的严丝合缝。

4. 实操全流程详解:从零开始的12步可复现部署指南

4.1 环境初始化:10分钟完成树莓派ROS基础环境

  1. 烧录系统:用Raspberry Pi Imager烧录ubuntu-20.04.6-preinstalled-server-arm64+raspi.img(Server版更轻量),首次启动时sudo raspi-config启用SSH、VNC、I2C、SPI,并将GPU内存设为16MB(释放更多RAM给ROS);
  2. 网络配置sudo nano /etc/netplan/01-network-manager-all.yaml,设静态IP(如192.168.1.100),避免DHCP变动导致ROS master通信失败;
  3. 更新源sudo sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list,换清华源;
  4. 安装ROS Noetic:按官网步骤,sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE886847RAA9AF4C4946sudo apt update && sudo apt install ros-noetic-desktop-full
  5. 初始化ROS环境echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc && source ~/.bashrc
  6. 安装依赖sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
  7. 初始化rosdepsudo rosdep init && rosdep update
  8. 创建工作空间mkdir -p ~/catkin_ws/src && cd ~/catkin_ws && catkin_make && source devel/setup.bash
  9. 安装鱼香ROSwget https://gitee.com/roswiki/fishros/raw/master/install.sh && bash install.sh,选择“ROS Noetic + Ubuntu 20.04”;
  10. 验证安装roscore后台运行,rosrun rospy_tutorials talker.py,另开终端rostopic list应见/chatter,证明ROS通信正常。
    这10步必须手敲,不可用脚本一键包——因为每一步的报错信息(如rosdep密钥过期、apt源404)都是排查后续问题的线索。我见过有人跳过第3步换源,结果apt install卡在ros-noetic-navigation下载,耗时2小时。

4.2 RPLIDAR A3驱动部署:三行命令点亮激光雷达

  1. 硬件连接:A3 USB线接树莓派USB2.0口(非USB3.0),雷达开关拨至ON,绿色指示灯常亮;
  2. 安装驱动cd ~/catkin_ws/src && git clone https://github.com/robopeak/rplidar_ros.git && cd ~/catkin_ws && catkin_make
  3. 权限配置sudo usermod -a -G dialout $USER,重启树莓派,确保当前用户有USB设备权限;
  4. 测试驱动roslaunch rplidar_ros rplidar.launch,若终端输出[INFO] ... RPLIDAR is connected,则成功;
  5. 验证数据rostopic hz /scan应显示average rate: 10.000rostopic echo /scan/ranges[0]应为有效数值(非infnan)。
    注意:若roslaunch报错Failed to open serial port,执行ls -l /dev/ttyUSB*,若显示crw-rw---- 1 root dialout,则权限正确;若为crw-rw---- 1 root root,则sudo usermod -a -G dialout $USER未生效,需重启。这是90%初学者卡住的第一关。

4.3 DWA导航栈配置:复制粘贴就能跑的最小可行配置

~/catkin_ws/src下创建my_robot包:

cd ~/catkin_ws/src && catkin_create_pkg my_robot rospy roscpp std_msgs geometry_msgs nav_msgs tf

my_robot/launch中新建dwa_nav.launch

<launch> <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" output="screen"> <param name="publish_frequency" value="50.0"/> </node> <include file="$(find turtlebot3_navigation)/launch/move_base.launch"/> <node pkg="dwa_local_planner" type="dwa_planner_ros" name="dwa_planner" output="screen"/> </launch>

my_robot/cfg中放dwa_local_planner_params.yaml(内容见3.4节),关键参数:

DWAPlannerROS: acc_lim_x: 0.8 acc_lim_y: 0.0 acc_lim_theta: 3.2 max_vel_x: 0.3 min_vel_x: 0.05 max_vel_theta: 1.0 min_vel_theta: -1.0 yaw_goal_tolerance: 0.05 xy_goal_tolerance: 0.1 sim_time: 0.7 path_distance_bias: 32.0 goal_distance_bias: 24.0 occdist_scale: 0.01 forward_point_distance: 0.325 stop_time_buffer: 0.2 scaling_speed: 0.25 max_scaling_factor: 0.2

然后cd ~/catkin_ws && catkin_make && source devel/setup.bash。启动命令:roslaunch my_robot dwa_nav.launch。此时rviz中添加RobotModelLaserScan,应见小车模型和激光点云。若/cmd_vel无输出,检查move_base是否报错The origin for the sensor at (0.0, 0.0, 0.0) is out of map bounds——这意味着map坐标系未加载,需先运行roslaunch turtlebot3_navigation turtlebot3_navigation.launch加载地图。

4.4 实车电机控制实现:Python PID闭环代码实录

my_robot/src中新建motor_control.py

#!/usr/bin/env python3 import rospy from geometry_msgs.msg import Twist from std_msgs.msg import Int32 import pigpio import time class MotorController: def __init__(self): self.pi = pigpio.pi() # GPIO setup: AIN1=17, AIN2=27, PWMA=18, BIN1=22, BIN2=23, PWMB=13 self.pi.set_mode(17, pigpio.OUTPUT) self.pi.set_mode(27, pigpio.OUTPUT) self.pi.set_mode(18, pigpio.HARD_PWM) self.pi.set_mode(22, pigpio.OUTPUT) self.pi.set_mode(23, pigpio.OUTPUT) self.pi.set_mode(13, pigpio.HARD_PWM) self.wheel_base = 0.26 # m self.max_vel = 0.3 # m/s self.pwm_freq = 1000 self.pi.hardware_PWM(18, self.pwm_freq, 0) self.pi.hardware_PWM(13, self.pwm_freq, 0) rospy.Subscriber("/cmd_vel", Twist, self.cmd_vel_callback) rospy.loginfo("Motor controller initialized") def cmd_vel_callback(self, msg): # Convert twist to PWM linear_x = msg.linear.x angular_z = msg.angular.z left_vel = linear_x - angular_z * self.wheel_base / 2 right_vel = linear_x + angular_z * self.wheel_base / 2 # Clamp to max velocity left_vel = max(-self.max_vel, min(self.max_vel, left_vel)) right_vel = max(-self.max_vel, min(self.max_vel, right_vel)) # Convert to PWM (0-255) left_pwm = int(255 * abs(left_vel) / self.max_vel) right_pwm = int(255 * abs(right_vel) / self.max_vel) # Set direction if left_vel >= 0: self.pi.write(17, 1); self.pi.write(27, 0) else: self.pi.write(17, 0); self.pi.write(27, 1) if right_vel >= 0: self.pi.write(22, 1); self.pi.write(23, 0) else: self.pi.write(22, 0); self.pi.write(23, 1) # Set PWM self.pi.hardware_PWM(18, self.pwm_freq, left_pwm * 10000) self.pi.hardware_PWM(13, self.pwm_freq, right_pwm * 10000) if __name__ == '__main__': rospy.init_node('motor_controller') mc = MotorController() rospy.spin()

保存后chmod +x motor_control.py,运行rosrun my_robot motor_control.py。此代码直接解析/cmd_vel,无中间ROS节点,延迟<5ms。注意pigpio需提前安装:sudo apt install pigpio python3-pigpio,且sudo systemctl start pigpiod

4.5 全流程联调:从Gazebo到实车的无缝切换

联调不是顺序执行,而是分层验证:

  1. 传感器层rostopic hz /scan确认激光数据在线;
  2. TF层rosrun tf view_frames生成PDF,检查map→odom→base_link→laser链完整;
  3. 规划层rostopic echo /move_base/cmd_vel,发布2D Nav Goal,观察/cmd_vel是否输出非零值;
  4. 执行层rostopic echo /cmd_velrostopic hz /scan同屏显示,确认两者频率一致;
  5. 实车层:小车通电,roslaunch my_robot dwa_nav.launchrviz中设Goal,小车应启动。
    若某层失败,立即隔离:例如/cmd_vel有输出但小车不动,则问题在电机控制层,检查motor_control.py日志;若/scan无数据,则回溯RPLIDAR驱动。我坚持“一层一验证”,拒绝“全堆一起调”,因为树莓派资源有限,多节点并发会让问题相互掩盖。

5. 常见问题与独家排查技巧:那些手册里不会写的“踩坑实录”

5.1 Gazebo仿真卡顿:不是性能问题,而是显卡驱动冲突

现象:rviz

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询