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