Wheeled robot motion via python

Isaac Sim Version

4.5.0
4.2.0
4.1.0
4.0.0
4.5.0
2023.1.1
2023.1.0-hotfix.1
Other (please specify):

Operating System

Ubuntu 22.04
Ubuntu 20.04
Windows 11
Windows 10
Other (please specify):

GPU Information

  • Model: NVIDIA RTX 3500 Ada Generation
  • Driver Version: 565.57.01

Topic Description

I am trying to drive a Locobot in Isaac Sim using Python code. The robot file is an URDF.

I tried to do it by creating an action graph via Python, but nothing worked when sending the velocity command via the ros topic. I have checked the connections, the joint, etc., multiple times.

After a bit of research, I guessed that from Python code, the robot should be controlled via Wheeled Robots [omni.isaac.wheeled_robots].

The robot also has an arm, but I only focus on his Kobuki base. I followed the documentation for the Wheeled robot and also checked the URDF documentation . However, I am still unable to move the robot. But I noticed that when the simulation is loaded, and I send velocity command via the ros topic, surprisingly, the robot arm moves while I am using “apply_wheel_actions.”

Code functions

The functions responsible of the robot import and the motion

def _load_robot(self):
        try:
            import_config = _urdf.ImportConfig()
            import_config.merge_fixed_joints = True
            import_config.fix_base = False
            import_config.self_collision = True
            import_config.create_physics_scene = True

            status, prim_path = omni.kit.commands.execute(
                'URDFParseAndImportFile',
                urdf_path=self.urdf_path,
                import_config=import_config
            )
            
            if not status:
                raise RuntimeError("URDF import failed")

            stage = omni.usd.get_context().get_stage()
            if not stage.GetPrimAtPath(prim_path):
                raise RuntimeError(f"Invalid prim path: {prim_path}")

            self.robot_path = prim_path
            simulation_app.update()

            self.wheeled_robot = WheeledRobot(
                prim_path=self.robot_path,
                name="locobot_base",
                wheel_dof_names=["wheel_left_joint", "wheel_right_joint"]
            )

            self.world.scene.add(self.wheeled_robot)
            self.wheeled_robot.initialize()
            
            self._configure_wheels()
            self._setup_velocity_control()
            
            simulation_app.update()

        except Exception as e:
            raise RuntimeError(f"Robot loading failed: {str(e)}")

    def _configure_wheels(self):
        if hasattr(self.wheeled_robot, '_articulation_view'):
            dof_props = self.wheeled_robot.dof_properties
            wheel_indices = [
                self.wheeled_robot.get_dof_index("wheel_left_joint"),
                self.wheeled_robot.get_dof_index("wheel_right_joint")
            ]

            for idx in wheel_indices:
                dof_props[idx]['driveMode'] = 1
                dof_props[idx]['stiffness'] = 0.0
                dof_props[idx]['damping'] = self.wheel_params["damping"]
                dof_props[idx]['maxEffort'] = self.wheel_params["max_effort"]

            self.get_logger().info(f"Wheels configured: indices={wheel_indices}")

    def _setup_velocity_control(self):
        self.create_subscription(Twist, '/cmd_vel', self._on_cmd_vel, 10)

    def _on_cmd_vel(self, msg):
        try:
            if not hasattr(self, 'wheeled_robot'): return

            # Convert m/s to stage units
            linear_vel = msg.linear.x * 100  # Scale up for better response
            angular_vel = msg.angular.z 

            # Calculate wheel velocities (rad/s)
            left_wheel = (linear_vel - angular_vel * self.wheel_params["wheel_distance"]) / self.wheel_params["wheel_radius"]
            right_wheel = (linear_vel + angular_vel * self.wheel_params["wheel_distance"]) / self.wheel_params["wheel_radius"]

            drive = ArticulationAction()
            drive.joint_velocities = np.array([left_wheel, right_wheel])

            self.wheeled_robot.apply_wheel_actions(drive)
            self.world.step(render=True)
            simulation_app.update()

        except Exception as e:
            self.get_logger().error(f"Velocity command failed: {str(e)}")
                

Screenshots or Videos

Additional Information

The robot wheels parameters

        self.wheel_params = {
            "wheel_radius": 0.033,
            "wheel_distance": 0.23,
            "max_linear_speed": 2.0,
            "max_angular_speed": 4.0,
            "max_wheel_speed": 10.0,
            "damping": 500.0,
            "max_effort": 5000.0

Based on your description, it seems that the control command is applied to the robot arm joint instead of the wheel joints. Could you please double check if the joints name are correct?

Or if you can, please feel free to share a minimal setup of your system so I can try to replicate on my end to help debug. Thanks

Also it is recommended to use Isaac Sim 4.5.0, which is the latest version.

1 Like

Hi, thank you for answering.

The joint names are correct. I migrated to Isaac Sim 4.5.0, and it worked.

I suspected an error in the Isaac Sim function implementation for the moving wheeled robot. However, with time, I discovered “UrdfJointTargetType.JOINT_DRIVE_POSITION”, and I started to think that since I couldn’t find this parameter, the robot joints were all set to position. Thus, no base motion was allowed. Nevertheless, switching to “UrdfJointTargetType.JOINT_DRIVE_VELOCITY” did not solve it. Only after upgrading was I able to make it move.

Maybe I was wrong since I am still figuring out how the simulation works.

1 Like