ROS2 Vehicle SDK control

Isaac Sim Version

4.5.0

Operating System

Ubuntu 22.04

GPU Information

  • Model: RTX 4090
  • Driver Version: 550.163.01

Topic Description

How can I control a vehicle created with the PhysX Vehicle SDK using ROS2 ?

Detailed Description

I have been using a modified OgnAckermannController node to send torque commands to a wheeled robot. To do so, I created an OmniGraph that subscribes to speed and angular targets and at the end of the graph I have Articulation Controllers nodes that target each wheel related to the Articulation root. It works well.

Now, I want to use a more accurate vehicle model. I have been trying to adapt the Physics Demo Scenes that uses PhysxVehicleControllerAPI to send the acceleration and steer commands to the vehicle. At the moment, one can control the vehicle using the keyboard. I want to replace that mode and send such commands using ROS. But I don’t understand how to connect the ROS graph nodes to the vehicle as with the ackermann scenes. Is it even possible ? How is the controller connected with the keyboard ? I cannot find the script that connects the keyboard events to the controller.

Cheers,

Bryan

Ok guys, I found a way.

A possibility is to simply add a graph containing the ROS2 subscriber and Odometry if necessary like so:


def graph_twist(self)
    # with self.targetPrim = "/World/Vehicle" targeting your rigid body vehicle
    : print("Graph") og.Controller.edit(
          {
            "graph_path" : "/ROS2Ackermann",
            "evaluator_name" : "execution"
          },
          {
            og.Controller.Keys.CREATE_NODES : [
              ("onPlaybackTick", "omni.graph.action.OnPlaybackTick"),
              ("readSimTime", "isaacsim.core.nodes.IsaacReadSimulationTime"),
              ("computeOdom", "isaacsim.core.nodes.IsaacComputeOdometry"),
              ("publishOdom", "isaacsim.ros2.bridge.ROS2PublishOdometry"),
              ("subscribeTwist", "isaacsim.ros2.bridge.ROS2SubscribeTwist"),
              ("QoSSensor", "isaacsim.ros2.bridge.ROS2QoSProfile"),
            ],
            og.Controller.Keys.SET_VALUES : [
              ("computeOdom.inputs:chassisPrim", [Sdf.Path(self.targetPrim)]),
              ("subscribeTwist.inputs:topicName", "/car/cmd_vel"),
              ("publishOdom.inputs:topicName", "/car/odom"),
              ("QoSSensor.inputs:createProfile", "Sensor Data"),
            ],
            og.Controller.Keys.CREATE_ATTRIBUTES : [],
            og.Controller.Keys.CONNECT : [
              ("onPlaybackTick.outputs:tick", "computeOdom.inputs:execIn"),
              ("onPlaybackTick.outputs:tick", "publishOdom.inputs:execIn"),
              ("readSimTime.outputs:simulationTime",
               "publishOdom.inputs:timeStamp"),
              ("computeOdom.outputs:angularVelocity",
               "publishOdom.inputs:angularVelocity"),
              ("computeOdom.outputs:linearVelocity",
               "publishOdom.inputs:linearVelocity"),
              ("computeOdom.outputs:orientation",
               "publishOdom.inputs:orientation"),
              ("computeOdom.outputs:position", "publishOdom.inputs:position"),
              ("onPlaybackTick.outputs:tick", "subscribeTwist.inputs:execIn"),
              ("QoSSensor.outputs:qosProfile",
               "subscribeTwist.inputs:qosProfile"),
              ("QoSSensor.outputs:qosProfile","publishOdom.inputs:qosProfile"),
            ],
          }, )

And retrieve the message fields that you are interested in like the control inputs and odometry data using:

def create(self, stage):
    self.graph_twist() # create the graph first then target the graph fields
    self.ros_linear_inputs = og.Controller.attribute("/ROS2Ackermann/subscribeTwist.outputs:linearVelocity")
    self.ros_angular_inputs = og.Controller.attribute("/ROS2Ackermann/subscribeTwist.outputs:angularVelocity")

Finally, by overloading the demo.Base update method, you can update the physxVehicleController directly:

def update(self, stage, dt, viewport, physxIFace):
        if self.vehicle_prim and self.ros_linear_inputs and self.ros_angular_inputs:
            torque_commands = og.DataView(self.ros_linear_inputs)
            torques_val = np.array(torque_commands.get())
            steer_commands = og.DataView(self.ros_angular_inputs)
            steer_val = np.array(steer_commands.get())

            # deal with data, clamping...
            # update the controller with linearVelocity.x and angularVelocity.z
            self.vehicle_prim.GetAttribute('physxVehicleController:accelerator').Set(torques_val[0])
            self.vehicle_prim.GetAttribute('physxVehicleController:steer').Set(steer_val[2])
        return

I my case I send torque commands.

The keyboard control can be deactivated by unchecking “Input Enabled” in the side panel of the vehicle in “Vehicle Controller Settings”

Best,

Bryan

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.