Ensure all arrays in the JointState command message have the same size#101
Ensure all arrays in the JointState command message have the same size#101srmainwaring wants to merge 3 commits intoros-controls:mainfrom
Conversation
The JointState messages requires the position, velocity and effort arrays are all the same size or empty in order to uniquely associate each joint name with the correct state. Signed-off-by: Rhys Mainwaring <rhys.mainwaring@me.com>
| joint_state.name.resize(joints.size()); | ||
| joint_state.position.resize(joints.size(), 0.0); | ||
| joint_state.velocity.resize(joints.size(), 0.0); | ||
| joint_state.effort.resize(joints.size(), 0.0); |
There was a problem hiding this comment.
| joint_state.effort.resize(joints.size(), 0.0); | |
| joint_state.effort.resize(joints.size(), std::numerical_limits::quiet_NaN()); |
| // https://docs.ros.org/en/api/sensor_msgs/html/msg/JointState.html | ||
| joint_state.name.resize(joints.size()); | ||
| joint_state.position.resize(joints.size(), 0.0); | ||
| joint_state.velocity.resize(joints.size(), 0.0); |
There was a problem hiding this comment.
I'm not sure if we should set zeros here as default
There was a problem hiding this comment.
Changed to NaN. Example after change now outputs:
ros2 topic echo -f /robot_joint_commands --once
header:
stamp:
sec: 31
nanosec: 833000000
frame_id: ''
name:
- rear_left_wheel_joint
- rear_right_wheel_joint
- left_wheel_steering_joint
- right_wheel_steering_joint
- front_left_wheel_joint
- front_right_wheel_joint
position:
- .nan
- .nan
- 0.0
- 0.0
- .nan
- .nan
velocity:
- 3.3330395907534287
- 3.3336270759132383
- .nan
- .nan
- .nan
- .nan
effort:
- .nan
- .nan
- .nan
- .nan
- .nan
- .nan
---Signed-off-by: Rhys Mainwaring <rhys.mainwaring@me.com>
Sure. At present the two tests are for robots that only have a position command interface, and a joint ordering such that this issue is not exposed. It will need a separate test, for something like an ackermann steering controlled vehicle that mixes different command interfaces. |
For now, just extend the test of the existing one by checking that the elements are of same size and are filled with NaNs for instance. |
Added in 13c65f3 There is an additional test for an ackermann steering controller in this branch: https://github.com/srmainwaring/topic_based_hardware_interfaces/tree/prs/joint-state-vector-sizes-with-ackermann-test which can be added if required. It is a stronger test of the indexing than the current tests as it includes both position and velocity command interfaces. Could you please approve the workflow execution. Tests pass locally. |
Signed-off-by: Rhys Mainwaring <rhys.mainwaring@me.com>
89d4f2f to
13c65f3
Compare
The tool was specifically design this way to be compatible with different simulators. For example Isaac sim does not allow you to specify position and velocity commands for a singe joint at the same time (the position command conflicts with the velocity and it doesn't know which one to ignore). You should not be creating hardware interface groups that require different command interface types (position, velocity, effort, ...). For example most mobile bases require a velocity interface to the wheels and the manipulator requires position interfaces to its joints. This means you have to create two hardware interfaces, one for the base and a second for the manipulator. If your hardware supports switching between position and velocity control then you need to be sure you only claim one at at time otherwise the receiving system has no way of knowing which command values in the JointState message are in control. |
|
If you wanted to do a hardware interface that supported mixed command interface types you would need to guarantee that all commanding controllers were smart enough to only set the interface they are allowed to. For example if you were using the JTC and mixing |
|
@MarqRazz, the proposed change is not to allow each joint to have multiple command types within a single hardware interface, but for a controller and hardware interface to allow each joint to be associated with the command type it requires: some joints may be position controlled, others velocity. I don't think this is incompatible with Isaac Sim or other simulators. Certainly Gazebo supports such controllers and the As an example, I don't think that these changes will break existing usage, but would be happy to check if there are examples the maintainers would like examined.
I think this is expected behaviour given the JointState message definition. That's what I see from the ackermann_steering controller at least. |
I have tired to control a mobile base with velocity controlled wheels and arm joints with position and wasn't able to make it work in Isaac sim which is what drove the code to be implemented this way. I haven't had a chance to play much with Isaac lately so it will take me some time to get a valid environment working again. I'm not saying it's impossible to do it in Isaac sim but changes are likely required to the simulator to support ignoring commands with values of NaN. Right now the simulator won't run if you send mixed interface types (position & velocity) and I have not tired sending joint commands of NaN to the Isaac Articulation controller. For my robot I command the mobile base on the topic /base_joint_commands and the arms are on their own topic/hardware interface. You can still support the <ros2_control name="ackermann_steering_system" type="system">
<hardware>
<plugin>joint_state_topic_hardware_interface/JointStateTopicSystem</plugin>
<param name="joint_commands_topic">/robot_position_commands</param>
<param name="joint_states_topic">/robot_joint_states</param>
</hardware>
<joint name="left_wheel_steering_joint">
<command_interface name="position" />
<state_interface name="position" />
<state_interface name="velocity" />
<state_interface name="effort" />
</joint>
<joint name="right_wheel_steering_joint">
<command_interface name="position" />
<state_interface name="position" />
<state_interface name="velocity" />
<state_interface name="effort" />
</joint>
<joint name="front_left_wheel_joint">
<state_interface name="position" />
<state_interface name="velocity" />
<state_interface name="effort" />
</joint>
<joint name="front_right_wheel_joint">
<state_interface name="position" />
<state_interface name="velocity" />
<state_interface name="effort" />
</joint>
</ros2_control>
<ros2_control name="ackermann_propulsion_system" type="system">
<hardware>
<plugin>joint_state_topic_hardware_interface/JointStateTopicSystem</plugin>
<param name="joint_commands_topic">/robot_velocity_commands</param>
<param name="joint_states_topic">/robot_joint_states</param>
</hardware>
<joint name="rear_left_wheel_joint">
<command_interface name="velocity" />
<state_interface name="velocity" />
<state_interface name="position" />
<state_interface name="effort" />
</joint>
<joint name="rear_right_wheel_joint">
<command_interface name="velocity" />
<state_interface name="position" />
<state_interface name="velocity" />
<state_interface name="effort" />
</joint>
</ros2_control> |
| sensor_msgs::msg::JointState joint_state; | ||
|
|
||
| // The JointState message definition requires that all arrays in the message | ||
| // should have the same size, or be empty. |
There was a problem hiding this comment.
In this library we opted for them to be empty.

JointState messages require the position, velocity and effort arrays are all the same size or empty in order to uniquely associate each joint name with the correct state. The current behaviour is to only push_back commands on the supported interfaces which can result in position, velocity and effort arrays of different sizes. This prevents the joint name from being uniquely associated with its corresponding command.
Example
This example is adapted from the
ackermann_drive_exampleingz_ros2_control_demosand uses the following control block.Publish a twist to
/ackermann_steering_controller/referenceand inspect the output from the ackermann controller:Before
After
It may be better to initialise the command arrays with NaN to allow consumers of the message to differentiate between a command with value zero from one that is unset. The JointState message notes do not provide guidance on this.