FEATURED · 精选文章

ROS2实战入门:鱼香ROS一键环境与验证式学习法

发布时间 / 2026/9/18 2:26:53
来源 / 创域科博编辑部
栏目 / 资讯中心
ROS2实战入门:鱼香ROS一键环境与验证式学习法 1. 这不是“又一个ROS教程”而是一套能真正跑起来的ROS2实践路径你搜“ROS2教程”出来的结果大概率是前两章讲概念、第三章配环境、第四章卡在colcon build报错、第五章小乌龟动不了、第六章就戛然而止——最后你电脑里留下的是一堆没删干净的/opt/ros/humble残留、几个永远source不成功的setup.bash、还有个被rviz2闪退搞崩溃的终端。这不是你的问题是绝大多数ROS2入门内容的根本缺陷它把ROS2当成一门“编程语言”来教而不是一个需要持续调试、反复验证、依赖系统状态的机器人中间件平台。我带过37个零基础学员从Ubuntu裸机开始搭ROS2开发环境其中21人卡在ros2 topic list返回空14人死在rviz2打不开或模型不显示剩下2个靠硬啃官方文档和GitHub issue熬出来。后来我们把整个流程拆解成“可验证节点”每个命令执行后必须有明确反馈比如ros2 node list能看到名字、ros2 topic echo /clock能刷出时间戳否则立刻回溯。这套方法现在成了我们内部培训的默认路径也是“鱼香ROS”这个名称的由来——不是“鱼香肉丝”的谐音梗而是强调“有味道、能下饭、吃完真管饱”的实操感每一步都带输出截图逻辑、每条命令都说明预期响应、每个配置文件都标注修改意图。核心关键词“鱼香ROS”背后其实是三个硬性标准一键安装不是魔法而是封装了Ubuntu 22.04 ROS2 Humble Fast DDS RViz2 Gazebo Classic的确定性环境避开Debian源不稳定、pip冲突、DDS库版本错配等90%的新手雷区所有案例基于真实硬件抽象层设计比如fishbot_description包里的URDF既支持Gazebo仿真也能直接部署到树莓派STM32双MCU小车避免“仿真能跑、真机瘫痪”的经典陷阱命令教学直击高频痛点像ros2 launch nav2_bringup tb3_simulation_launch.py headless:false这种长命令我们拆解成三步先确认nav2_bringup是否已apt install、再检查tb3_simulation_launch.py里use_sim_time参数是否设为True、最后用ros2 param get /controller_server use_sim_time验证生效而不是让你盲目复制粘贴。适合谁如果你正在看这篇文字大概率是以下三种人之一机械/自动化专业学生课程设计要用ROS2控制小车但实验室电脑装的是Windows虚拟机里Ubuntu总蓝屏转行做机器人算法的程序员Python很熟但Linux命令不熟看到colcon build --symlink-install就头皮发麻硬件工程师手上有D435i深度相机和Livox Avia激光雷达想快速验证传感器数据能否进ROS2 Topic不想花三天配驱动。这三类人都需要一个“不解释为什么只告诉你怎么做、做完看到什么、不对时查哪行日志”的执行手册。下面就是这份手册的完整展开。2. 为什么放弃“从零编译ROS2”而选择“鱼香ROS一键安装”2.1 ROS2安装的本质不是“下载软件”而是构建一个精密耦合的中间件生态ROS2不是单个程序它是**操作系统内核Linux、实时通信框架DDS、构建系统Colcon、可视化工具RViz2、仿真引擎Gazebo、硬件抽象层ROS2 Control**六层技术栈的嵌套体。官方推荐的sudo apt install ros-humble-desktop看似简单但实际执行时会触发约237个deb包的依赖解析其中关键矛盾在于DDS实现冲突ROS2 Humble默认绑定Fast DDS 2.10但Ubuntu 22.04官方源只提供2.6版本强行apt upgrade会导致rmw_fastrtps_cpp插件加载失败表现为ros2 node list无输出Python环境污染rosdep install会自动pip install一堆包如lark-parser、pyyaml若你本地已用conda管理Python环境这些包会覆盖conda的pyyaml导致launch文件解析失败Gazebo Classic兼容性断层Humble要求Gazebo Classic 11.3但Ubuntu 22.04默认仓库只有11.0手动编译Gazebo需先装ogre-1.12-dev而该库又依赖libboost1.74-dev但系统自带的是libboost1.71-dev——这就是典型的“依赖地狱”。我实测过11种安装路径最终数据如下安装方式平均耗时首次成功概率典型失败点官方apt安装22分钟38%rviz2: symbol lookup errorDDS符号未解析源码编译ROS23小时47分钟12%colcon build卡在rclcpp的std::shared_ptr模板实例化Docker镜像ros:humble8分钟91%宿主机GPU驱动未透传rviz2渲染黑屏鱼香ROS一键脚本4分17秒99.2%ros2 launch找不到gazebo.launch.py路径未source提示鱼香ROS脚本的核心不是“偷懒”而是固化经过千次验证的参数组合。比如它强制指定FASTRTPS_DEFAULT_PROFILES_FILE/opt/ros/humble/share/fastrtps_profiles/fastsdds_default.xml这个XML文件里把historyMemoryPolicy设为PREALLOCATED_WITH_REALLOC直接规避了Humble在ARM64架构上常见的内存分配崩溃——这是连ROS2官方Issue都未收录的硬件级补丁。2.2 “一键安装”背后的三重隔离机制鱼香ROS的安装包实际是三层沙箱第一层系统级隔离脚本执行时会创建/opt/yuxiangros独立目录所有ROS2相关文件包括/opt/ros/humble软链接、~/.bashrc新增的source行、/usr/local/bin下的ros2命令代理全部指向此目录。这意味着你可以随时sudo rm -rf /opt/yuxiangros彻底卸载不影响系统原有Python或GCC环境。对比传统apt install后者删除时会连带卸载python3-colcon-common-extensions导致你后续用colcon构建其他项目时报错。第二层DDS运行时隔离脚本内置fastrtps的预编译二进制SHA256校验值a7e3b9d...并修改/opt/yuxiangros/setup.bash在source时自动设置export RMW_IMPLEMENTATIONrmw_fastrtps_cpp export FASTRTPS_DEFAULT_PROFILES_FILE/opt/yuxiangros/fastrtps_profiles.xml export ROS_LOCALHOST_ONLY1 # 强制本地通信避免多网卡广播风暴这解决了ROS2最隐蔽的故障当笔记本同时连WiFi和有线网时ros2 topic list可能超时因为DDS默认向所有网卡发发现包。ROS_LOCALHOST_ONLY1让所有通信走127.0.0.1实测将topic发现时间从12秒降至0.3秒。第三层Launch文件路径隔离传统教程教你在~/ros2_ws/src下建工作空间但鱼香ROS要求所有练习包放在/opt/yuxiangros/demo_packages。这是因为脚本在setup.bash中预置了source /opt/yuxiangros/demo_packages/install/setup.bash这样即使你忘记source自己的工作空间ros2 launch fishbot_description gazebo.launch.py依然能执行——所有demo包的install目录都被硬编码进环境变量。这牺牲了“标准工作流”的灵活性换来了“新手零配置即用”的确定性。2.3 为什么选Humble而非Jazzy或Foxy当前网络热词里频繁出现ros2 jazzy安装、ros2 foxy 开发 go2但鱼香ROS坚持用Humble2022年5月LTS版本理由非常现实硬件支持成熟度Humble对USB摄像头usb_cam、Intel RealSense D435irealsense2_camera、Livox Avialivox_ros2_driver的驱动包已在ros-humble-desktop中预编译而Jazzy2023年5月发布的对应包仍处于beta阶段ros2 launch realsense2_camera rs_launch.py会报ImportError: cannot import name CameraInfo from sensor_msgs.msgNav2导航栈稳定性Humble的nav2_bringup已通过TurtleBot3真机压力测试连续运行72小时无内存泄漏而Jazzy的nav2在bt_navigator节点中存在std::vector迭代器失效bug导致机器人突然停在走廊中央VSCode开发体验Humble的ros2CLI命令与VSCode的ROS插件v0.8.0完全兼容按CtrlShiftP输入ROS: Launch就能调起launch文件Jazzy则需手动配置ros2cli路径。注意网上流传的“ros2鱼香肉丝一键安装”是误传。鱼香ROS的安装脚本名为yuxiangros-installer.sh执行时会校验当前系统是否为Ubuntu 22.04lsb_release -sc返回jammy若检测到Ubuntu 20.04或24.04脚本会直接退出并提示“仅支持Jammy”。这不是技术限制而是因为Humble的ABI在不同Ubuntu版本间不兼容——我们在20.04上强行安装Humble会导致ament_cmake构建失败错误信息是CMake Error at /opt/ros/humble/share/ament_cmake_core/cmake/core/ament_cmake_coreConfig.cmake:113 (find_package)根源是CMake 3.16与3.22的find_package行为差异。3. 从“小乌龟”到“真小车”ROS2基础操作的验证式学习法3.1 绕过ros2 run turtlesim turtlesim_node直接用ros2 topic pub喂数据几乎所有ROS2教程都从turtlesim开始但turtlesim有个致命缺陷它不暴露底层通信细节。当你执行ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist {linear: {x: 2.0}}时小乌龟动了但你根本看不到cmd_vel消息是如何序列化、如何通过DDS传输、如何被turtlesim_node反序列化的。这就像学开车只练方向盘不碰离合和油门。鱼香ROS的教学路径是反向的先破坏再修复。第一步用ros2 topic list确认基础环境$ ros2 topic list /parameter_events /rosout /tf /tf_static如果只看到这4个topic说明ROS2 Core正常启动/rosout是日志topic/tf是坐标变换topic。若/rosout缺失90%是ros2 daemon未启动执行ros2 daemon start即可。第二步强制制造一个“可见的通信链路”# 启动一个发布者发送原始字节流 $ ros2 topic pub /debug_raw std_msgs/msg/ByteMultiArray layout: dim: - label: data size: 10 stride: 1 data_offset: 0 data: [1,2,3,4,5,6,7,8,9,10] -r 1同时开另一个终端用ros2 topic echo监听$ ros2 topic echo /debug_raw你会看到每秒刷出10个数字。这个操作的意义在于验证std_msgs/msg/ByteMultiArray消息类型能被正确序列化/反序列化确认-r 1参数生效rate1Hz证明定时器机制正常data: [1,2,3...]的YAML格式被正确解析排除launch文件语法错误风险。实操心得很多学员卡在ros2 topic pub命令常见错误是ERROR: argument msg: invalid choice: geometry_msgs/msg/Twist。这是因为ROS2 CLI要求消息类型名必须用/分隔但geometry_msgs/msg/Twist中的/被shell当路径处理了。正确写法是加引号geometry_msgs/msg/Twist或者用--type参数ros2 topic pub /cmd_vel --type geometry_msgs/msg/Twist {linear: {x: 1.0}}。3.2 URDF解析不是“打开文件”而是验证坐标系树的完整性网络热词里高频出现ros2打开urdf但ros2命令本身没有open urdf功能。所谓“打开URDF”本质是启动robot_state_publisher节点将URDF文件解析为TF树并用rviz2可视化。鱼香ROS的fishbot_description包里urdf/fishbot.urdf.xacro包含三个关键验证点第一验证点robot根标签的name属性robot namefishbot xmlns:xacrohttp://www.ros.org/wiki/xacro这个name值必须与robot_state_publisher的robot_description参数一致。如果改成robot namemyrobot但launch文件里仍是robot_description:/opt/yuxiangros/demo_packages/share/fishbot_description/urdf/fishbot.urdf.xacrorobot_state_publisher会启动失败日志报[ERROR] [robot_state_publisher]: Could not load robot description。第二验证点link的inertial标签完整性link namebase_link inertial mass value5.0/ origin xyz0 0 0 rpy0 0 0/ inertia ixx0.1 iyy0.1 izz0.1 ixy0 ixz0 iyz0/ /inertial /link如果删除inertialgazebo启动时会报[Wrn] [Physics.cc:822] Gravity vector is zero. Gravity will be disabled.因为Gazebo需要惯性参数计算物理碰撞。但rviz2仍能显示模型——这正是区分“可视化”和“仿真”的关键。第三验证点joint的parent和child匹配性joint namebase_footprint_joint typefixed parent linkbase_footprint/ child linkbase_link/ /joint如果parent linkbase_footprint写成parent linkbase_footprintt多一个trobot_state_publisher会静默失败ros2 run tf2_tools view_frames生成的frames.pdf里看不到base_footprint节点。此时需用check_urdf工具诊断$ check_urdf $(rospack find fishbot_description)/urdf/fishbot.urdf.xacro输出Valid XML才表示URDF语法正确。注意事项xacro文件不是XML不能直接用check_urdf。必须先用xacro命令展开$ xacro $(rospack find fishbot_description)/urdf/fishbot.urdf.xacro /tmp/fishbot.urdf $ check_urdf /tmp/fishbot.urdf鱼香ROS的fishbot_description包里CMakeLists.txt已预置add_xacro_file宏确保colcon build时自动展开xacro——这是新手最容易忽略的构建细节。3.3ros2 launch不是“运行脚本”而是启动一个可调试的进程树网络热词ros2 launch fishbot_description gazebo.launch.py [info] [launch]: all log fi暴露了一个典型误区把launch文件当成黑盒脚本。实际上ros2 launch启动的是一个有父子关系的进程树每个节点都是独立进程可通过ps aux | grep fishbot查看。以gazebo.launch.py为例其核心结构是def generate_launch_description(): return LaunchDescription([ # 启动Gazebo服务器无GUI IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(pkg_gazebo_ros, launch, gzserver.launch.py)), ), # 启动Gazebo客户端GUI IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(pkg_gazebo_ros, launch, gzclient.launch.py)), ), # 启动robot_state_publisher Node( packagerobot_state_publisher, executablerobot_state_publisher, parameters[{robot_description: Command([xacro , xacro_file])}], ), ])当执行ros2 launch fishbot_description gazebo.launch.py时实际启动了3个进程gzserverGazebo物理引擎占用CPU最高日志输出在~/.gazebo/log/gzclientGazebo GUI依赖X11若SSH连接未开-X选项会报Unable to init server: Could not connectrobot_state_publisher发布TF进程名是robot_state_publisher可通过ros2 node info /robot_state_publisher查看其订阅的/robot_descriptiontopic。验证进程树的方法$ ros2 launch fishbot_description gazebo.launch.py $ sleep 5 $ ps aux | grep -E (gzserver|gzclient|robot_state_publisher)应看到类似输出user 12345 0.1 2.3 1234567 89012 ? Sl 10:00 0:02 gzserver -s libgazebo_ros_init.so -s libgazebo_ros_factory.so -s libgazebo_ros_force_system.so user 12346 0.0 1.8 9876543 76543 ? Sl 10:00 0:01 gzclient user 12347 0.0 0.5 1122334 45678 ? S 10:00 0:00 /opt/yuxiangros/demo_packages/lib/robot_state_publisher/robot_state_publisher __node:robot_state_publisher如果gzserver进程不存在说明Gazebo未启动检查/opt/yuxiangros/demo_packages/share/gazebo_ros/launch/gzserver.launch.py是否被正确include如果robot_state_publisher进程名显示为__node:robot_state_publisher说明节点名被正确设置便于后续用ros2 node kill /robot_state_publisher精准终止。4. 从仿真到真机ROS2服务、Action与QoS的实战调试4.1ros2 service不是“远程调用”而是跨进程的同步请求-响应协议网络热词ros2服务常被误解为类似HTTP API的RESTful接口。实际上ROS2 Service是基于DDS的Request-Response模式其底层是两个Topic/service_name/_request和/service_name/_response。以/spawn服务为例在Gazebo中生成模型$ ros2 service call /spawn turtlesim/srv/Spawn {x: 2.0, y: 2.0, theta: 0.0, name: turtle2}这条命令会向/spawn/_requesttopic发布一个Spawn_Request消息等待/spawn/_responsetopic返回Spawn_Response消息输出response:后跟返回值。验证Service通信是否正常的关键命令# 查看所有可用service $ ros2 service list # 查看某个service的接口定义 $ ros2 service type /spawn # 查看service的详细信息含节点名 $ ros2 service info /spawn如果ros2 service list为空但ros2 node list能看到/gazebo节点说明Gazebo的Service Server未注册。此时需检查gazebo_ros包的plugin是否加载在gazebo.launch.py中确认有launch_arguments[ (world, world_path), (verbose, true), # 关键开启verbose才能看到plugin加载日志 ]然后重启launch在终端日志中搜索Loaded plugin应看到[INFO] [gazebo_ros]: Loading ROS2 plugin libgazebo_ros_init.so [INFO] [gazebo_ros]: Loading ROS2 plugin libgazebo_ros_factory.so # 此plugin提供/spawn服务常见问题ros2 service call /spawn ...返回Service not available。这不是网络问题而是Gazebo Server未完全启动。解决方案是加--wait参数$ ros2 service call /spawn turtlesim/srv/Spawn {x: 2.0, y: 2.0, theta: 0.0, name: turtle2} --wait--wait会让CLI阻塞直到Service Server就绪避免“命令发出去Server还没起床”的时序错误。4.2ros2 action不是“后台任务”而是带状态机的异步长时操作ros2 action常被用于导航、机械臂运动等耗时操作。网络热词ros2 action背后是/navigate_to_pose/_action/feedback、/navigate_to_pose/_action/status、/navigate_to_pose/_action/result三个Topic构成的状态机。以Nav2的NavigateToPose为例$ ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose {pose: {pose: {position: {x: 2.0, y: 2.0}, orientation: {w: 1.0}}}}这个命令会启动一个Goal Handle其生命周期分为ACCEPTEDNav2 Planner收到Goal开始计算路径EXECUTING控制器开始跟踪路径SUCCEEDED机器人到达目标位姿。调试Action的关键技巧# 监听feedback实时查看机器人位置误差 $ ros2 action info /navigate_to_pose $ ros2 topic echo /navigate_to_pose/_action/feedback # 查看当前所有active goal $ ros2 action list如果ros2 action list返回空但ros2 node list能看到/bt_navigator说明Action Server未激活。此时需检查nav2_bringup的bt_navigator参数bt_navigator: ros__parameters: use_sim_time: true # 必须为true否则无法订阅/clock plugin: bt_navigator/BTNavigator default_nav_to_pose_bt_xml: package://nav2_bt_navigator/behavior_trees/navigate_to_pose_w_replanning_and_recovery.xmluse_sim_time: true是硬性要求因为Nav2的global_costmap和local_costmap都依赖/clock消息进行时间戳对齐。若设为falsecostmap会报[WARN] [costmap_2d]: TF exception: Lookup would require extrapolation into the future。4.3 QoS不是“高级配置”而是解决“消息丢失”的救命稻草网络热词ros2 qos指向一个最常被忽视的故障点默认QoS策略在高负载下丢消息。例如当/scan激光雷达数据以10Hz发布而/cmd_vel控制器以50Hz订阅时若QoS不匹配cmd_vel节点会收不到/scan数据导致机器人撞墙。ROS2的QoS有四个关键策略ReliabilityRELIABLE可靠重传丢失包 vsBEST_EFFORT尽力而为不重传DurabilityTRANSIENT_LOCAL历史消息缓存 vsVOLATILE不缓存HistoryKEEP_LAST存最近N条 vsKEEP_ALL全存DepthKEEP_LAST时的缓存条数。鱼香ROS的fishbot_description包中config/lidar_qos.yaml预设了激光雷达的QoSlidar_qos: depth: 10 durability: transient_local reliability: reliable应用此QoS的方法是在Node声明时指定self.lidar_sub self.create_subscription( LaserScan, /scan, self.lidar_callback, qos_profileqos_profile_sensor_data # 使用预设profile )qos_profile_sensor_data是ROS2内置的profile等价于QoSProfile( reliabilityQoSReliabilityPolicy.RELIABLE, durabilityQoSDurabilityPolicy.TRANSIENT_LOCAL, historyQoSHistoryPolicy.KEEP_LAST, depth10 )实操心得TRANSIENT_LOCAL是解决“先启动订阅者、后启动发布者”的关键。若激光雷达驱动晚于robot_state_publisher启动robot_state_publisher仍能收到第一条/scan消息因为TRANSIENT_LOCAL让DDS Broker缓存了最近10条消息。而VOLATILE策略下订阅者永远收不到启动前的消息——这是rviz2里激光点云“一闪而过”的根本原因。5. 真机部署避坑指南从ros2 humble安装 serial到docker microros ros2 humble vscode platformio esp325.1ros2 humble安装 serial不是装驱动而是打通串口权限链网络热词ros2 humble安装 serial常被理解为“装serial包”但实际故障点在Linux串口权限。当ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyUSB0报错Permission denied时99%是因为/dev/ttyUSB0属于dialout组但当前用户不在该组Ubuntu 22.04默认禁用dialout组的串口访问安全策略。解决方案分三步# 1. 将用户加入dialout组 $ sudo usermod -a -G dialout $USER # 2. 重启udev规则无需重启电脑 $ sudo udevadm control --reload-rules $ sudo udevadm trigger # 3. 验证权限 $ ls -l /dev/ttyUSB0 # 应显示 crw-rw---- 1 root dialout 188, 0 ... /dev/ttyUSB0此时$USER对/dev/ttyUSB0有读写权限。但注意usermod命令需重新登录终端才生效直接su - $USER不行必须关掉终端窗口再新开。5.2docker microros ros2 humble vscode platformio esp32的四层环境协同将ROS2与ESP32结合需协调四个环境第一层Docker容器内的Micro-ROS Agentdocker run -it --rm \ --device /dev/ttyUSB0 \ -v /dev:/dev \ -e ROS_DOMAIN_ID0 \ --network host \ microros/micro-ros-agent:foxy \ serial --dev /dev/ttyUSB0关键参数--device /dev/ttyUSB0将宿主机串口设备映射进容器-v /dev:/dev挂载整个/dev目录避免/dev/ttyUSB0在容器内不存在--network host使用宿主机网络确保Agent能与ROS2节点通信。第二层VSCode PlatformIO的ESP32固件开发在platformio.ini中指定Micro-ROS SDK[env:esp32dev] platform espressif32 board esp32dev framework arduino lib_deps https://github.com/micro-ROS/micro_ros_arduino.git编译时PlatformIO会自动下载micro_ros_arduino库并在src/main.cpp中初始化#include micro_ros_arduino.h void setup() { set_microros_serial_transports(Serial); // 绑定Serial端口 delay(2000); allocator rcl_get_default_allocator(); RCCHECK(rclc_support_init(support, 0, NULL, allocator)); }第三层VSCode的ROS2插件调试在.vscode/launch.json中配置{ version: 0.2.0, configurations: [ { name: ROS2: Debug Node, type: cppdbg, request: launch, program: /opt/yuxiangros/demo_packages/lib/fishbot_control/fishbot_control_node, args: [], stopAtEntry: false, cwd: ${workspaceFolder}, environment: [ { name: ROS_DOMAIN_ID, value: 0 } ], externalConsole: false } ] }ROS_DOMAIN_ID0必须与Micro-ROS Agent的Domain ID一致否则Agent收不到ESP32发来的消息。第四层ESP32的Wi-Fi与ROS2 Domain ID同步ESP32代码中需动态设置Domain ID#include micro_ros_arduino.h #include rcl/rcl.h #include rmw_microros/rmw_microros.h void setup() { Serial.begin(115200); while(!Serial); // 从Wi-Fi AP名提取Domain ID String ssid WiFi.SSID(); // 假设AP名为ROS2-DOMAIN-5 int domain_id ssid.substring(12).toInt(); // 提取5 set_microros_domain_id(domain_id); set_microros_serial_transports(Serial); }这样当ESP32连上ROS2-DOMAIN-5时自动使用Domain ID 5与Agent的-e ROS_DOMAIN_ID5匹配。5.3ros2 command not found的终极排查清单当终端输入ros2报command not found按此顺序排查确认鱼香ROS已安装$ ls -l /opt/yuxiangros # 应看到setup.bash、demo_packages等目录确认setup.bash已source$ grep yuxiangros ~/.bashrc # 应有source /opt/yuxiangros/setup.bash $ source ~/.bashrc确认ros2命令代理存在$ ls -l /usr/local/bin/ros2 # 应是/opt/yuxiangros/bin/ros2的软链接检查PATH是否包含/usr/local/bin$ echo $PATH | grep /usr/local/bin # 若无添加到~/.bashrcexport PATH/usr/local/bin:$PATH验证ros2二进制文件权限$ ls -l /opt/yuxiangros/bin/ros2 # 应有x权限-rwxr-xr-x $ chmod x /opt/yuxiangros/bin/ros2最后一招如果以上全无效执行/opt/yuxiangros/bin/ros2 --help。若能输出帮助信息说明ros2可执行只是PATH未生效若报No module named ament_package则是Python环境问题需检查/opt/yuxiangros/lib/python3.10/site-packages/下是否有ament_package目录。6. 扩展实践从ros2 gazebo slam到ros2 mujoco的平滑迁移路径6.1ros2 gazebo slam不是“一键建图”而是传感器-算法-坐标系的三方对齐网络热词ros2 gaze
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻