How to run ROS2 visualize_franka.sh with external /joint_state input

The visualize_franka.sh script from the franka_description uses the joint state publisher GUI which has a graphical interface that constantly publishes joint states:

Joint State Publisher GUI

While this is a great tool for interactively setting the joint positions, since it’s constantly publishing joint states, it blocks every other software from publishing joint states to the same topic. While you can publish joint states to the same topic, the GUI will just overwrite your joint state with its own.

Modifying franka_description to accept external joint states

To work around this, we need to modify the launch/visualize_franka.launch.py to not start the joint state publisher GUI. The robot state publisher will subscribe to /joint_states anyway, so you can just inject your own joint states into that topic.

The simple way to do it is to clone my fork, which has the modification already done and is based on my jazzy port of franka_description:

git clone -b external_joint_state https://github.com/ulikoehler/franka_description.git

You can also modify launch/visualize_franka.launch.py yourself: Just delete the Node() call that starts the joint state publisher GUI. The following diff shows you which lines to delete (the lines prefixed by -).

             robot_state_publisher_spawner_opaque_function,
-            Node(
-                package="joint_state_publisher_gui",
-                executable="joint_state_publisher_gui",
-                name="joint_state_publisher_gui",
-            ),
             Node(
                 package="rviz2",
                 executable="rviz2",

Running the modified script

Run visualize_franka.sh as usual:

./scripts/visualize_franka.sh arm_id:=fr3

Note that it will look weird at first, since rviz2 won’t know any default joint states. This is normal and expected:

RViz2 no default joint state

Which exact joint states does the robot_state_publisher expect?

First, I recorded the /joint_states topic using

ros2 topic echo /joint_states > joint_states.txt

Based on the output:

---
header:
  stamp:
    sec: 1736718274
    nanosec: 6300566
  frame_id: ''
name:
- fr3_joint1
- fr3_joint2
- fr3_joint3
- fr3_joint4
- fr3_joint5
- fr3_joint6
- fr3_joint7
- fr3_finger_joint1
- fr3_finger_joint2
position:
- -2.7437
- 0.8697321200000001
- 0.8121960000000001
- -2.2966916299999998
- -0.6359528999999999
- 2.9597191999999994
- 0.32752674000000015
- 0.038372
- 0.038372
velocity: []
effort: []

you can see that in our case, it expects 8 entries in the name field, and 8 entries in the position field. The velocity and effort fields are empty.

Publishing your own joint states

Now we can use the script from our post ROS2 Python script to publish custom joint states to publish our own joint states to the /joint_states topic.

By running the script from that post:

./publish_custom_joint_states.py

we can see that the robot moves according to the sinusoidal joint states we’re publishing:

Franka Custom Joint States