简介:本资源是面向高校机器人方向本科生与研究生的ROS2综合实践项目,聚焦全向移动机器人在未知环境中的自主建图、定位与路径规划全流程实现。项目基于ROS2 Humble/Foxy框架,整合激光SLAM(如slam_toolbox或nav2)、RRT与A等规划算法、CAN电机底层控制及omni_robot URDF模型,解决动态场景下实时避障与精准轨迹跟踪问题,适用于毕业设计、课程设计及智能机器人竞赛备赛。压缩包共212个文件,含102个Python节点脚本(覆盖传感器驱动、SLAM后端、路径跟踪与运动控制)、9个xacro宏定义(用于全向底盘建模)、8个YAML配置(导航参数与TF树设定)、6个自定义msg/srv接口及配套RVIZ可视化配置,整体4.07MB,结构清晰、模块解耦度高。已有96人学习下载,资源附带README.md使用说明与frames.pdf原理图解,可直接编译运行,助读者快速掌握ROS2导航栈集成、多节点协同调试与真实硬件闭环验证的关键能力。
1. 项目概述:从零到一,打造一个会思考的全向移动机器人
最近在整理硬盘,翻出来一个老项目,一个基于ROS2的SLAM全向机器人路径规划系统。这个项目当时是为了参加一个机器人挑战赛做的,核心目标很简单:让一个搭载激光雷达的麦克纳姆轮小车,在未知的室内环境里,自己建图、定位,然后规划出一条最优路径,从A点移动到B点,期间还得能避开突然出现的障碍物。听起来像是自动驾驶的“青春版”,对吧?实际上,这套技术栈正是当下服务机器人、仓储AGV乃至一些特种机器人的核心技术骨架。
这个项目打包成一个.zip文件,里面包含了URDF模型、启动文件、参数配置、导航栈配置以及一些测试用的地图和脚本。它不是一个玩具,而是一个可以直接在实体机器人或Gazebo仿真中跑起来的完整工程。对于刚接触ROS2和机器人导航的朋友来说,啃下这个项目,你就能打通从感知(SLAM建图)到决策(路径规划)再到控制(全向底盘运动)的完整链路。今天,我就把这个项目的里里外外拆解一遍,不仅告诉你每个模块怎么用,更会分享当时调试时踩过的坑和总结出的“骚操作”。
2. 核心架构与工具链选型解析
2.1 为什么是ROS2?
几年前做机器人,ROS1还是绝对主流。但这次我选择了ROS2,原因很直接:生产级需求。ROS1的通信机制基于TCPROS/UDPROS,单Master节点一旦崩溃,整个系统就瘫痪了,这在需要高可靠性的场合是致命的。ROS2采用的DDS(数据分发服务)通信中间件,天生就是去中心化的,没有单点故障问题。此外,ROS2对实时性、跨平台(Windows、Linux、RTOS)的支持,以及更精细的生命周期管理,都让它更适合未来的产品化部署。
在这个项目中,我们用的是ROS2 Humble Hawksbill版本,它长期支持到2027年5月,社区活跃,资料相对丰富,与Ubuntu 22.04搭配是天作之合。如果你用Ubuntu 20.04,可以选择ROS2 Foxy。
2.2 SLAM方案:Cartographer vs. SLAM Toolbox
SLAM(同步定位与建图)是机器人的“眼睛”和“记忆”。我们得让机器人在移动中,一边估算自己的位置(定位),一边绘制环境地图(建图)。项目里我对比测试了两个主流方案:
Google Cartographer:这是我们的最终选择。它是一个基于图优化的SLAM系统,特别擅长处理激光雷达数据。它的强大之处在于“回环检测”,当机器人再次回到一个曾经到过的地方时,它能识别出来并修正整个轨迹和地图的累积误差,从而得到一张全局一致的高精度地图。对于室内结构化环境,Cartographer的表现非常稳定。
- 实操心得:Cartographer的参数配置文件(
.lua文件)是调优的关键。特别是num_subdivisions_per_laser_scan(将一帧激光数据细分成的点数)和num_range_data(用于子图构建的帧数),需要根据你的激光雷达频率和机器人运动速度仔细调整。参数调不好,建出来的地图可能会“重影”或者扭曲。
- 实操心得:Cartographer的参数配置文件(
SLAM Toolbox:这是一个ROS社区内非常受欢迎的工具包,它同样基于图优化,但提供了纯定位模式。这意味着你可以先让机器人跑一遍建好图,然后加载这张图,让机器人在已知地图里进行高精度的实时定位。这个功能在导航阶段极其有用。
- 注意事项:SLAM Toolbox在资源受限的板子(如树莓派)上运行时,如果地图分辨率设置过高(如0.05米/像素),实时优化计算可能会成为瓶颈,导致定位延迟。通常0.05-0.1米的分辨率是平衡点。
最终方案:我们采用Cartographer 负责建图阶段,因为它建图精度高、全局一致性更好。建图完成后,保存地图(.pgm和.yaml)。在导航阶段,则切换到SLAM Toolbox 的纯定位模式,它比Cartographer的纯定位更轻量、更稳定。
2.3 导航与路径规划栈:Nav2
路径规划不是孤立的,它需要一套完整的导航框架来支撑,这就是Nav2。你可以把它理解为ROS2里的“自动驾驶大脑”。它接管了从接收目标点到控制轮子转动的所有决策任务。Nav2的核心是一个行为树(Behavior Tree),它优雅地组织了“全局规划-局部规划-恢复行为”等一系列动作。
我们的项目深度集成了Nav2,其工作流程可以概括为:
- 输入:当前机器人位姿(来自SLAM定位)、目标位姿(来自RVIZ2点击或程序发布)、代价地图(由传感器数据生成)。
- 全局规划器:在已知的全局代价地图上,规划一条从起点到终点的粗略路径。我们选用的是
NavFn或Smac Planner(后者支持更复杂的运动模型)。 - 局部规划器:负责跟随全局路径,同时处理实时传感器数据(如激光雷达),进行动态避障和局部路径调整。对于全向机器人,我们使用了
DWB(Dynamic Window Approach)的变体,因为它能很好地处理全向运动学模型。 - 控制器:将局部规划器输出的速度指令(
Twist消息,包含线速度和角速度)转换为底层电机可以执行的指令。对于麦克纳姆轮,这需要经过一轮运动学逆解算。 - 恢复行为:当机器人被困住(比如被临时围住)时,触发旋转、小范围后退等行为尝试脱困。
2.4 机器人平台:全向移动底盘的优势与挑战
我们用的是麦克纳姆轮组成的全向移动平台。这种底盘的优势显而易见:可以在不改变车头朝向的情况下,进行横向平移和任意方向的旋转。这给路径规划带来了巨大的灵活性,机器人可以像螃蟹一样横着走,在狭窄空间内机动性远超差速驱动模型。
但挑战也随之而来:
- 运动学解算复杂:需要将期望的
Twist速度指令,准确解算为四个轮子的独立转速。URDF模型和控制器里必须正确定义这套运动学。 - 对控制精度要求高:四个轮子的转速匹配必须非常精确,否则会产生额外的滑动和摩擦,不仅耗电,还会让定位(尤其是轮速计融合)产生误差。
- 成本与地面要求:麦克纳姆轮价格较高,且对地面平整度有一定要求,在粗糙地面表现会下降。
在项目配置中,我们在robot_description的URDF文件里正确定义了轮子的关节和传动,并在ros2_control的配置中,使用了一个diff_drive_controller的扩展或自定义控制器来处理全向运动学。
3. 项目环境搭建与核心配置详解
3.1 系统与ROS2基础环境
假设你有一台安装好Ubuntu 22.04的电脑或工控机(如Jetson系列)。第一步就是安装ROS2 Humble。
# 设置语言环境(避免后续出错) sudo apt update && sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8 # 添加ROS2软件源 sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update && sudo apt install curl -y sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null # 安装ROS2核心包 sudo apt update sudo apt install ros-humble-desktop python3-colcon-common-extensions -y # 配置环境变量(每次打开新终端都需要执行,或写入~/.bashrc) source /opt/ros/humble/setup.bash注意:网络上有很多“一键安装脚本”,例如“鱼香ROS”的脚本确实方便。但对于生产环境或想深入了解依赖关系的开发者,我强烈建议手动走一遍官方流程,这样出了问题你才知道从哪里查起。
3.2 创建工作空间与导入项目
将下载的基于ROS2的SLAM全向机器人路径规划.zip解压到你的ROS2工作空间中。
# 创建并进入工作空间 mkdir -p ~/ros2_ws/src cd ~/ros2_ws/src # 假设你的zip解压后得到一个名为 `omni_slam_nav` 的文件夹 # 将其拷贝到src目录下,或者直接在这里解压 cp -r /path/to/omni_slam_nav ./ # 返回工作空间根目录,安装依赖并编译 cd ~/ros2_ws rosdep install -i --from-path src --rosdistro humble -y colcon build --symlink-install # --symlink-install 参数创建符号链接,这样你修改python脚本后无需重新编译即可生效 # 激活工作空间 source ~/ros2_ws/install/setup.bash3.3 关键配置文件剖析
项目zip包里的配置文件是灵魂所在,理解它们你就能举一反三。
1. 机器人描述文件 (omni_bot.urdf.xacro)这是一个xacro文件,它用宏定义的方式更灵活地描述了机器人模型。里面定义了底盘尺寸、四个麦克纳姆轮的位置与关节、激光雷达(laser)的安装位置与链接、IMU(惯性测量单元)的链接等。特别要注意的是,<joint>的类型和<origin>的变换,这直接决定了后续robot_state_publisher能否正确发布TF树。TF树是ROS里描述所有坐标系关系的基石,定位、感知、规划都依赖它。
2. Cartographer配置文件 (cartographer_2d.lua)这个文件控制Cartographer的建图行为。你需要重点关注以下几个参数,并根据你的机器人硬件进行调整:
| 参数组 | 关键参数 | 说明与调整建议 |
|---|---|---|
TRAJECTORY_BUILDER_2D | num_accumulated_range_data | 累积多少帧激光数据才进行一次扫描匹配。机器人移动快,这个值可以小点(如1);移动慢或追求精度,可以大点(如3)。 |
submaps.num_range_data | 一个子图(submap)由多少帧激光数据构成。影响子图的细节和优化规模。通常20-30。 | |
motion_filter.max_angle_radians | 运动过滤器:机器人旋转超过这个角度才处理一帧数据。防止原地微小转动产生过多冗余数据。 | |
POSE_GRAPH | optimize_every_n_nodes | 每添加n个节点(位姿点)就进行一次图优化。值越小,实时性越好但计算量大;值越大,优化延迟长但单次优化更充分。60-90是常用值。 |
constraint_builder.sampling_ratio | 回环检测的采样率。值越小,搜索回环越频繁,计算量越大,但回环闭合更快。0.3是个不错的起点。 |
3. Nav2导航配置文件 (nav2_params.yaml)这是Nav2的主配置文件,篇幅很长,我们挑核心的讲。
- 全局代价地图插件:通常使用
voxel_layer(体素层)处理3D传感器(如深度相机)或obstacle_layer(障碍层)处理2D激光雷达。它定义了如何将传感器数据转换为地图中的障碍物信息。 - 全局规划器参数:例如
NavFn的tolerance(目标点容差)和use_astar(是否使用A*算法,默认为Dijkstra)。对于大部分室内场景,Dijkstra算法规划的路径更平滑。 - 局部规划器参数 (DWB):这是调参的重灾区。
sim_time:模拟未来多长时间的轨迹。太短则前瞻性不足,太长则计算量大。1.0-2.0秒是常用范围。vx_samples,vy_samples,vtheta_samples:在速度空间(线速度x, 线速度y, 角速度)中采样的数量。全向机器人需要vy_samples(横向速度)。数量越多,搜索的轨迹越多,质量可能更高,但计算更慢。通常每个维度10-20个样本。path_distance_bias,goal_distance_bias,occdist_scale:轨迹评价函数的权重。分别代表“贴合全局路径的程度”、“靠近目标点的程度”、“远离障碍物的程度”。你需要根据机器人行为来调整。比如机器人总是撞向障碍物,就提高occdist_scale;如果总是远离路径,就提高path_distance_bias。
4. 启动文件 (bringup.launch.py)这是ROS2的Python启动文件,它像乐高说明书一样,把各个节点按顺序组装并启动起来。它会依次启动:
robot_state_publisher:发布机器人TF树。joint_state_publisher:发布轮子等关节状态(如果使用Gazebo仿真,则由仿真器提供)。cartographer_node或slam_toolbox_node:SLAM节点。nav2_bringup:整个Nav2导航栈,包括地图服务器、AMCL(如果不用SLAM Toolbox定位)、生命周期管理器等。
4. 实战演练:从建图到自主导航全流程
4.1 第一步:在Gazebo中仿真与建图
如果你没有实体机器人,Gazebo仿真是最佳的起步点。我们的项目包通常包含了世界文件和机器人模型。
# 启动Gazebo仿真环境和机器人 ros2 launch omni_slam_nav gazebo.launch.py # 或者,如果launch文件命名不同,可能是 ros2 launch omni_slam_nav simulation.launch.py这时Gazebo会打开,你的全向机器人模型出现在一个预设的环境中(比如一个模拟的仓库或走廊)。接着,启动Cartographer进行建图:
# 启动建图节点和RVIZ2可视化工具 ros2 launch omni_slam_nav mapping.launch.py在RVIZ2中,你需要添加以下显示项:
LaserScan:查看激光雷达数据是否正常。TF:查看坐标系是否正确连接(通常以base_link或base_footprint为根)。Map:订阅/map话题,实时观看地图构建过程。
现在,你可以通过另一个终端发布速度指令来控制机器人探索环境:
ros2 topic pub -r 10 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}"让机器人缓慢地走遍环境的每一个角落,尤其要记得让机器人走回之前经过的地方,形成回环。当你看到地图不再变化且闭合良好时,就可以保存地图了:
# 首先,切换到保存地图的服务调用(假设使用nav2_map_server) ros2 run nav2_map_server map_saver_cli -f ~/ros2_ws/src/omni_slam_nav/maps/my_map这会在指定目录下生成my_map.pgm(地图图像)和my_map.yaml(地图元数据)两个文件。
4.2 第二步:切换至导航与定位模式
建图完成后,关闭建图相关的节点。现在我们要在已知地图里进行导航。
修改启动配置:通常项目会有一个专门的导航启动文件,例如
navigation.launch.py。你需要在这个文件中,将SLAM节点替换为地图服务器和定位节点。如果使用SLAM Toolbox定位,配置会类似这样:# 在launch文件中,注释掉Cartographer节点,添加: slam_toolbox_node = Node( package='slam_toolbox', executable='localization_slam_toolbox_node', name='slam_toolbox', output='screen', parameters=[{ 'use_sim_time': use_sim_time, 'map_file_name': 'path/to/your/my_map', 'mode': 'localization' # 关键!切换到纯定位模式 }] )启动导航栈:
ros2 launch omni_slam_nav navigation.launch.py在RVIZ2中设置初始位姿:启动后,地图会加载,但机器人不知道自己在哪。在RVIZ2工具栏点击
2D Pose Estimate,然后在地图上机器人实际所在的大概位置点击并拖拽,给出一个初始朝向。这时,你会看到激光扫描点云与地图的障碍物逐渐对齐,定位就完成了。
4.3 第三步:路径规划与动态避障测试
定位成功后,就可以发送导航目标了。
- 发送目标点:在RVIZ2工具栏点击
Nav2 Goal,然后在地图上任意可通行区域点击并拖拽,设定目标位置和朝向。 - 观察行为:机器人会规划出一条全局路径(通常显示为绿色线条),然后开始移动。局部规划器会生成一系列蓝色的预测轨迹,并选择最优的一条(通常为红色或黄色)来执行。你会看到机器人平滑地跟随路径,并在遇到Gazebo中临时加入的障碍物时,自动绕行。
- 测试全向特性:尝试发送一些需要横向移动的目标。观察机器人是否灵活地使用了侧向移动,而不是像差动机器人那样先旋转再前进。
实操心得:在测试动态避障时,故意在机器人行进路线上快速加入一个障碍物(在Gazebo中拖入一个盒子)。观察局部规划器的反应速度。如果机器人撞上去了,可能需要调整DWB的sim_time(加长前瞻时间)或者occdist_scale(提高避障权重)。同时,检查代价地图中inflation_radius(膨胀半径)的设置,它决定了障碍物在地图上“膨胀”多大,给机器人留出安全空间。
5. 移植到实体机器人:关键步骤与避坑指南
仿真跑通只是第一步,真正的挑战在实体机器人上。以下是移植的核心步骤和必坑点。
5.1 硬件接口与驱动
底盘串口通信:大多数机器人底盘通过串口或CAN总线接收速度指令。你需要一个ROS2节点,订阅
/cmd_vel话题,将geometry_msgs/msg/Twist消息解算为你的底盘协议(例如,通过串口发送特定的字节数组)。这个节点通常需要自己编写,或者使用底盘厂商提供的SDK进行封装。- 避坑点:串口权限问题。在Linux下,确保你的用户有读写串口设备的权限(通常需要将用户加入
dialout组,或者设置udev规则)。
- 避坑点:串口权限问题。在Linux下,确保你的用户有读写串口设备的权限(通常需要将用户加入
传感器驱动:
- 激光雷达:确保你的雷达(如思岚A1、禾赛等)有对应的ROS2驱动包。驱动会发布
sensor_msgs/msg/LaserScan消息到/scan话题。检查扫描角度、范围、频率等参数是否在Cartographer配置中匹配。 - IMU:IMU数据用于融合定位,提高精度。驱动会发布
sensor_msgs/msg/Imu消息。关键:确保IMU的坐标系(imu_link)与base_link之间的TF变换正确,并且IMU数据的朝向(特别是四元数)符合ROS标准(REP-103)。
- 激光雷达:确保你的雷达(如思岚A1、禾赛等)有对应的ROS2驱动包。驱动会发布
里程计:机器人通常通过轮子编码器计算里程计。你需要一个节点,读取编码器数据,通过运动学正解算,发布
nav_msgs/msg/Odometry消息到/odom话题,并广播从odom坐标系到base_link坐标系的TF变换。- 避坑点:这是误差的主要来源。编码器分辨率、轮子半径、轮距测量必须极其精确。麦克纳姆轮还存在滑动问题,纯里程计漂移会很大,因此必须依赖激光SLAM进行校正。
5.2 传感器标定与时间同步
- 激光雷达与底盘外参标定:雷达安装在机器人上,它的坐标系
laser_link相对于base_link有一个固定的变换(平移和旋转)。这个变换如果不准,建图时就会“歪”。你可以手动测量,但更准的方法是使用自动标定工具(如cartographer自带的cartographer_autogenerate_ground_truth工具,或ipa_calibration)。 - 时间同步:多个传感器(激光雷达、IMU、摄像头)的数据时间戳必须同步。硬件同步最好(如使用PTP),软件同步次之。在ROS2中,确保所有驱动节点都使用相同的时钟源(
use_sim_time参数在实物运行时设为false)。
5.3 实机建图与导航调试
- 实地建图:选择一个特征丰富的环境,缓慢、平稳地操控机器人走遍全场。务必走回环。实物建图比仿真难,因为地面不平、雷达噪声、轮子打滑等因素都会引入误差。如果建图出现严重重影或错位,按以下顺序排查:
- 检查TF树是否稳定、正确(在RVIZ2中查看
TF,看有没有警告)。 - 调高Cartographer的
submaps.num_range_data,让子图更“坚固”。 - 检查IMU数据是否正常融合(在Cartographer配置中启用
use_imu_data)。
- 检查TF树是否稳定、正确(在RVIZ2中查看
- 导航参数重调:仿真参数不能直接用于实物。实物电机响应有延迟,惯性更大。
- 降低最大速度:在DWB和控制器配置中,将
max_vel_x,max_vel_y,max_rot_vel先设到较低值(如仿真速度的一半)。 - 调整控制频率:提高控制器发布命令的频率(如从10Hz提高到20Hz),使控制更细腻。
- 增大代价地图膨胀半径:给实物机器人留出更大的安全余量。
- 降低最大速度:在DWB和控制器配置中,将
6. 进阶优化与问题排查实录
6.1 性能优化技巧
- 降低地图分辨率:导航用的代价地图分辨率不需要像建图那么高。将
global_costmap和local_costmap的resolution从0.05提高到0.1,可以显著减少计算量。 - 限制局部代价地图大小:
local_costmap的width和height只需比机器人尺寸大一些即可(如5x5米),没必要覆盖全局。 - 选择性使用传感器:在
local_costmap的sources列表中,只添加必要的传感器(如激光雷达),避免深度相机等数据量大的传感器,除非必要。
6.2 常见问题与解决方案速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| RVIZ2中看不到激光数据 | 1. 激光雷达驱动未启动或崩溃。 2. TF树断裂, laser_link未连接到base_link。3. RVIZ2中 LaserScan话题订阅错误。 | 1. `ros2 topic list |
| 建图时地图扭曲、重影 | 1. 里程计误差过大(轮子打滑、编码器不准)。 2. Cartographer参数不适配(扫描匹配失败)。 3. IMU数据异常或未正确使用。 | 1. 检查/odom话题数据是否平滑,尝试降低机器人移动速度。2. 调整 TRAJECTORY_BUILDER_2D下的ceres_scan_matcher相关参数,或减小max_range(忽略远处噪声)。3. 确认IMU话题已正确配置到Cartographer参数中。 |
| 导航时机器人原地打转或不走直线 | 1. 定位漂移(AMCL或SLAM Toolbox定位不准)。 2. 控制器参数不合适,特别是PID参数。 3. 全局/局部路径规划器目标点容差设置过大。 | 1. 重新给出准确的2D Pose Estimate。检查定位点云与地图匹配度。2. 调整 controller_server中控制器的xy_goal_tolerance和yaw_goal_tolerance,将其改小(如0.05, 0.1)。3. 检查DWB的轨迹评分函数权重,确保 path_distance_bias足够高。 |
| 遇到动态障碍物反应迟钝或撞上 | 1. 局部代价地图更新频率低。 2. DWB的 sim_time太短,或轨迹采样数太少。3. 传感器数据延迟大。 | 1. 提高local_costmap的update_frequency(如从1Hz提高到5Hz)。2. 增加 sim_time(如到2.0秒),增加vx_samples等采样数。3. 使用 ros2 topic hz /scan检查激光数据频率,优化驱动或网络。 |
| 全向移动时轨迹不平滑,有抖动 | 1. 底层电机控制周期与ROS导航控制周期不匹配。 2. 速度指令解算到轮速时,未做平滑滤波。 3. DWB为全向模型生成的轨迹本身就不平滑。 | 1. 在速度指令发布节点和电机驱动节点间加入低通滤波器,平滑速度指令。 2. 尝试使用 TEB(Timed Elastic Band)局部规划器替代DWB,它对全向模型的支持可能更好,但计算量更大。 |
6.3 扩展方向
这个项目是一个强大的基础平台,你可以在此基础上进行很多扩展:
- 多传感器融合:引入视觉摄像头,使用
robot_localization包融合轮速计、IMU、视觉里程计,实现更鲁棒的定位。 - 三维导航:使用3D激光雷达或深度相机,配合
nav2的voxel_nav或smac_planner的3D版本,实现多层空间或崎岖地形的导航。 - 任务与行为编排:利用Nav2的行为树(BT)功能,编写自定义的行为节点,实现“巡逻到A点 -> 等待5秒 -> 拍照 -> 返回充电桩”等复杂任务序列。
- 云端监控与调度:通过
rosbridge_suite建立WebSocket接口,开发一个网页后台,可以远程监控多个机器人的状态、下发任务、查看实时地图。
从解压一个ZIP包,到让机器人在复杂环境里自如穿梭,这个过程充满了挑战,但每解决一个问题,你对机器人系统的理解就加深一层。这个项目最宝贵的不是那几千行代码和配置文件,而是你在调试TF树、啃参数文档、分析问题日志过程中积累的“工程直觉”。希望这份超详细的拆解,能帮你少走些弯路,更快地享受到机器人自主移动带来的乐趣和成就感。
本文还有配套的精品资源,点击获取