為什麼 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_trajectory 等 command 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)啟動指令
bashros2 launch ur5_description bringup_gazebo.launch.py use_control:=false use_gui:=true
-
Gazebo 會用內建關節馬達;GUI 能直接拖動,RViz/Gazebo 一起動。
4 ️⃣ 真實控制情境啟動指令
bashros2 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 控制範例,隨時告訴我!
沒有留言:
張貼留言