2025年7月4日 星期五

為什麼 joint_state_publisher_gui 動不到 Gazebo 裡的 UR5?

為什麼 joint_state_publisher_gui 動不到 Gazebo 裡的 UR5?

元件作用實際訊號流向
joint_state_publisher_gui讓你用滑桿改「/joint_states」訊息只影響 TF/RVIZ,不發任何 command
Gazebo model透過 <gazebo_ros2_control> plugin 把機械手臂當 hardware_interface期待 controller 透過 /joint_trajectory_controller/joint_trajectorycommand topic 來驅動
結果GUI 只改 RViz 角度,Gazebo 仍停在 0°看起來「不互動」

一旦你在 URDF 裡引入 ros2_control plugin,Gazebo 會把所有關節鎖給控制器;
GUI 發出的 /joint_states 對物理模擬 完全無效


改善方案一覽

方案適用情境做法概要
A. Demo/教學,只想拉桿看手臂動不需要真實物理移除 ros2_control plugin → Gazebo 用預設關節馬達
或乾脆不開 Gazebo、只在 RViz 看
B. 真實模擬,要用控制器運動規劃 / MoveIt保留 ros2_control,但 關掉 GUI,改用
rqt_joint_trajectory_controller、MoveIt、或 CLI 送 trajectory
C. 仍想保留 GUI,但讓它驅動控制器研究/測試加一個小橋接節點:把 GUI 內 /joint_states 轉成
trajectory_msgs/JointTrajectory 丟給 /joint_trajectory_controller

具體修改作法(推薦)

1 ️⃣ 替 launch 增加開關參數

python
# bringup_gazebo.launch.py from launch.conditions import UnlessCondition, IfCondition ... ld.add_action( DeclareLaunchArgument('use_gui', default_value='false') ) ld.add_action( DeclareLaunchArgument('use_control', default_value='true') ) ... # joint_state_publisher_gui 只有在 use_gui==true AND use_control==false 才啟動 joint_state_publisher_gui_node = Node( package='joint_state_publisher_gui', executable='joint_state_publisher_gui', condition=IfCondition(LaunchConfiguration('use_gui') & UnlessCondition(LaunchConfiguration('use_control'))) )

2 ️⃣ 在 URDF/Xacro 把 ros2_control plugin 包進條件

xml
<!-- ur5_ros2_control.xacro --> <xacro:arg name="use_control" default="true"/> <xacro:if value="${use_control}"> <gazebo> <plugin name="gazebo_ros2_control" filename="libgazebo_ros2_control.so"> <parameters>$(arg hardware_config)</parameters> </plugin> </gazebo> </xacro:if>

3 ️⃣ Demo 情境(僅 GUI)啟動指令

bash
ros2 launch ur5_description bringup_gazebo.launch.py use_control:=false use_gui:=true
  • Gazebo 會用內建關節馬達;GUI 能直接拖動,RViz/Gazebo 一起動。

4 ️⃣ 真實控制情境啟動指令

bash
ros2 launch ur5_description bringup_gazebo.launch.py use_control:=true use_gui:=false
  • /joint_trajectory_controller 接管,MoveIt 或腳本送軌跡。


想把 GUI 直接驅動控制器?(進階)

python
# gui_to_trajectory_bridge.py (簡化示例) import rclpy, yaml from sensor_msgs.msg import JointState from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint JOINTS = ["shoulder_pan_joint", "shoulder_lift_joint", ...] # ur5 joints def cb(msg, pub): traj = JointTrajectory() traj.joint_names = JOINTS point = JointTrajectoryPoint() point.positions = [msg.position[msg.name.index(j)] for j in JOINTS] point.time_from_start.sec = 1 traj.points.append(point) pub.publish(traj) rclpy.init() node = rclpy.create_node('gui_to_traj') pub = node.create_publisher(JointTrajectory, '/joint_trajectory_controller/joint_trajectory', 10) node.create_subscription(JointState, '/joint_states', lambda m: cb(m, pub), 10) rclpy.spin(node)

把這個 node 加進 launch,GUI 滑桿就真的能「推動」Gazebo 關節了。


小結 🚀

  • joint_state_publisher_gui ≠ 控制器
    它只改視覺化;有 ros2_control 時必須用對應 command topic。

  • launch 參數或 xacro 條件 乾淨地分離「示範 GUI」與「真實控制」兩種模式最簡單。

  • 若要兼得 GUI+物理,需額外橋接 /joint_states → trajectory

照以上改動後,joint_state_publisher_gui 的 “不互動” 問題就能釐清並依需求解決。如果還需要示範完整的修正檔或 MoveIt 控制範例,隨時告訴我!

沒有留言:

張貼留言