r/ROS

▲ 20 r/ROS

[ROS2 Humble / Nav2] Robot spins continuously when goal requires rotation — only reaches straight-line goals

Setup:

- ROS2 Humble, real robot (4WD)

- Nav2 with AMCL localization

- SmacPlanner2D (global) + DWB local planner

- EKF odometry fusion (`/odometry/filtered`)

- Map present, AMCL working, teleop working fine

Issue:

Robot navigates perfectly to goals that are directly in front of it (straight line). As soon as the goal requires any rotation — curved path or goal behind the robot — it starts spinning in place endlessly. Looks like it enters recovery spin behavior and never exits.

Github Link (config files and terminal log can be found here):

https://github.com/Anandhu-Sudha/my-ros-bot.git

Has anyone faced this exact issue? What is the reason for this recovery behavior loop? Any fix suggestions appreciated.

u/An2s1 — 1 day ago
▲ 10 r/ROS

Before you switch to Cyclone, check your serial link

Saw another "just use Cyclone" comment today, got little tired of this honestly

For me it's not even real choice as I work with micro-ROS and Fast DDS is hardcoded in micro-ROS agent on host side. Switching to Cyclone just means extra integration work for nothing.

Also I think people are optimizing wrong thing in general. In our case serial link between microcontroller and host was the biggest latency contributor, not DDS at all. Took us embarrassingly long time to realize this lol

So before going deep into DDS comparison, first check where your actual bottleneck is. And if you do compare, test on your own hardware, don't trust numbers from internet. Setup is too different everywhere to make general conclusions.

If anyone's actually swapped the RMW in their micro-ROS agent, would like to know how that went. Doesn't seem worth it to me.

reddit.com
u/NickShipsRobots — 1 day ago
▲ 3 r/ROS

Trying to get started.

Hello people of reddit. I just wanted to all u fine fellows how to get started with robotics. Ive been interested in it for quite some time, even made a lfr with arduino but copied the code from github. I don really know if this is the best way to start or is there a proper way to get by learning. So please shower me with your amazing advices masters. 🚀

reddit.com
u/traumatizeddd1 — 2 days ago
▲ 30 r/ROS

Hey, Anybody intrested in a Remote Robotics Simulation Engineer Job? $180/hr - $200/hr

DM me for more

What You'll Do

  • Design and implement high-fidelity robot models (URDF/MJCF) with accurate kinematics, dynamics, and contact properties
  • Build and maintain simulation environments using MuJoCo, NVIDIA Isaac Sim, and/or Gazebo
  • Develop end-to-end simulation pipelines for robot training, testing, and validation
  • Tune physics parameters — friction, damping, inertia, actuator models — to maximize sim-to-real transfer
  • Integrate simulations with ROS2 for perception, planning, and control workflows
  • Write clean, performant code in Python and/or C++ to support simulation infrastructure
  • Collaborate asynchronously with robotics researchers and engineers on model accuracy and environment design
  • Profile and optimize simulation performance for large-scale or parallelized runs
  • Document simulation configurations, model parameters, and pipeline architecture

Requirements

  • Strong hands-on experience with at least one major robotics simulator: MuJoCo, NVIDIA Isaac Sim, or Gazebo
  • Proficient in Python and/or C++ in a robotics or scientific computing context
  • Solid understanding of rigid-body dynamics, contact mechanics, and control theory
  • Experience creating and validating robot models (URDF, MJCF, or SDF formats)
  • Familiarity with ROS2 and its integration with simulation environments
reddit.com
u/ApplicationRich5216 — 2 days ago
▲ 6 r/ROS+1 crossposts

Help curating a public library of the best physical AI models

Building out a public curated list of the best digital twin models (robots, environments, sim-ready assets).

End goal: an actively updating library with the most accurate ready versions of each robot publically accessible. These will be specifically used for IsaacLab and USD supporting simulators.

Already investigated:

NVIDIA Isaac Sim Assets: https://docs.isaacsim.omniverse.nvidia.com/5.1.0/assets/usd_assets_overview.html

Open source URDFs: https://www.urdfhub.com/

Gazebo Model: https://app.gazebosim.org/fuel/models

Can someone point me in a direction of where are the best available models currently being held?

reddit.com
u/Educational-Shoe733 — 2 days ago
▲ 186 r/ROS+1 crossposts

Finally made it !

Finally made it! 🎉

After 3 days of hard work and learning the basics of ROS2, I successfully built and simulated a 4x4 car model. 🚗

As a beginner, there was a steep learning curve, but the feeling of seeing it work makes it all worth it. Excited to keep building and expanding my skills from here! 💻🤖

#Robotics #ROS2 #Tech #ContinuousLearning #EmbeddedSystems

u/SeriousJudge8844 — 3 days ago
▲ 7 r/ROS+1 crossposts

Before a mobile robot hits hard E-stop: detecting wheel slip and odom jumps from /cmd_vel + /odom

Hi guys,

I’ve been working on a small ROS 2 project for AMR/AGV-style mobile robots.
Problem:
A robot may still be receiving valid velocity commands, but its physical motion no longer matches the command stream.
Examples:
- wheel slip on wet / oily floors
- odometry mismatch
- localization jumps
- stale / bursty velocity commands
- robot starts shaking or over-correcting before safety lidar / hardware E-stop cuts in

A normal timeout only checks:

Did a command arrive recently?

It does not check:

Is the robot still moving according to the command it was just given?

So I built a small inline ROS 2 topic filter:

/cmd_vel → Kinematic Guard → /safe_cmd_vel
                 ↑
               /odom

It has a passive observe mode first, so it can run without taking over control.

Example status:

{

"status": "RESYNCING",

"causalAlignment": "BROKEN",

"dominantCause": "WHEEL_SLIP",

"guardAction": "BRAKE_AND_RESYNC"

}

The demo does not need a real robot, Gazebo, or Isaac Sim. It uses a lightweight mock AMR/AGV and injects wheel slip.

GitHub:
https://github.com/ZC502/ros2_kinematic_guard

ROS Discourse discussion:
https://discourse.openrobotics.org/t/detecting-execution-collapse-before-hard-e-stop-ros2-kinematic-guard-for-ros-2-amr-agv/54944

I’d be interested in feedback from people who have dealt with mobile robot slip, odometry jumps, or unexpected hard E-stop events in the field.

reddit.com
u/Slight_Analysis_5414 — 3 days ago
▲ 77 r/ROS

Cubic Doggo full GitHub record: it can now walk and turn!

The walking video can be found here:
https://www.reddit.com/r/robotics/comments/1tghftd/cubic_doggo_full_github_record_it_can_now_walk/

But linking another video here instead. I just find it so cool that the robot moves in sync with RViz :)

Next steps will be to incorporate IMU using CHAMP:
https://github.com/chvmp/champ
If anyone has a recommendation on where to start, like a tutorial or guide, that would be much appreciated.

u/SphericalCowww — 4 days ago
▲ 2 r/ROS

[Help: UAV, SITL] Having trouble with VTOL transition in PX4-Autopilot

Disclaimer: I am not a Robotics/ROS person. I am an AI engineer by profession. So, I am new to all of this.

I am working on a VTOL quad tailsitter project. So, I need a simulation to work with. My management has been using Gazebo harmonic SIM and ArduPilot or PX4 for SITL. They were using quadcopter models for their previous projects hence they don't have any reference for the specific model we have. The physical model of the VTOL is an X-wing quad tailsitter.

I am using PX4 quadtailsitter which can be accessed through make px4_sitl gz_quadtailsitter and I exhausted more time than I should but I still couldn't perform a simple mission like go from A to B. The problem in my understanding is occurring during the transition phase. For some god forbidden reason, its not properly transitioning. I am using mavlink/mavsdk commands but I don't think that's the problem either since its not properly working even when I use pxh shell commands.

I don't what should I do. So, I would like to ask you guys to how to resolve this? If it's not resolvable or need more time investment to patch up, can you guys recommend some other easy and ready to use stack because I should start training my model as early as possible.

reddit.com
u/npc_xxx00 — 3 days ago
▲ 13 r/ROS

Why rclcpp? Why rclpy?

Hello all!

I am quite new to ROS2. I was wondering is there any reason one would write a node in C++ rather than Python and vice versa? Or is it just preference?
What are the pros-and-cons for each?

Thanks for your time!

reddit.com
u/Tranomial_2 — 4 days ago
▲ 10 r/ROS+2 crossposts

Semantic Navigation and Memory with Nav2 and ROS2

Hey everyone, wanted to share my project on semantic navigation where a robot can explore a simulated living room, remember what it has seen, and later navigate using natural-language object goals instead of coordinates.

For example, after exploration, you can ask it something like:

>

The system retrieves a remembered viewing pose for the object and sends a deterministic Nav2 goal.

Stack used:

  • ROS 2 Humble
  • Nav2
  • SLAM Toolbox
  • Ignition Gazebo Fortress
  • rosbridge / ROS-MCP
  • SQLite + JSON semantic memory
  • RGB camera, LiDAR, IMU, odometry in simulation

The idea was to move beyond “go to x, y” navigation and test a more semantic workflow:

  1. Robot explores the room
  2. Camera observer stores object captures
  3. Semantic memory keeps object labels and poses
  4. User asks for an object in natural language
  5. Robot navigates near the remembered object location using Nav2

It’s still a simulation demo, but I think this kind of object-based navigation is a useful bridge between classical robotics stacks and newer language/vision-based interfaces.

Video demo/tutorial:
https://youtu.be/Cj4dYQ7BuUw

Code:
https://github.com/itsbharatj/demos-ros-mcp-server/tree/example_10_semantic_navigation/10_semantic_navigation

Would love feedback from people working on robot navigation, semantic mapping, or VLM/LLM-based robotics systems. I’m especially curious about better ways to represent the semantic memory and make the object-goal selection more robust.

u/Evening-Woodpecker-1 — 4 days ago
▲ 2 r/ROS

Running Rtabmap using ZED2i but tf tree is causing errors...

The Error :

tabmap-3] [ WARN] (2026-05-18 20:24:22.858) MsgConversion.cpp:2010::getTransform() (getting transform base_link -> zed_left_camera_frame_optical) Lookup would require extrapolation into the future. Requested time 1779116062.012223 but the latest data is at time 1779116060.612197, when looking up transform from frame [zed_left_camera_frame_optical] to frame [base_link] (wait_for_transform=0.200000)

[rtabmap-3] [ERROR] (2026-05-18 20:24:22.858) MsgConversion.cpp:2182::convertRGBDMsgs() TF of received image for camera 0 at time 1779116062.012223s is not set!

[rtabmap-3] [ WARN] (2026-05-18 20:24:23.067) MsgConversion.cpp:2010::getTransform() (getting transform base_link -> zed_left_camera_frame_optical) Lookup would require extrapolation into the future. Requested time 1779116062.212203 but the latest data is at time 1779116060.612197, when looking up transform from frame [zed_left_camera_frame_optical] to frame [base_link] (wait_for_transform=0.200000)

[rtabmap-3] [ERROR] (2026-05-18 20:24:23.067) MsgConversion.cpp:2182::convertthRGBDMsgs() TF of received image for camera 0 at time 1779116062.212203s is not set!

I cant make out what the exact problem is but ig something to do with time mismatch between tf and depth image

TF Tree

I tried to broadcast time on all transforms but that also causes the same error currecntly zed camera link -> zed camera center till the optical frames is being published by zed wrapper and the rest are just static transforms with odom -> base link beind done by an ekf filter node
# Bridge IMU to Camera

imu_frame_fix = Node(

package='tf2_ros',

executable='static_transform_publisher',

name='imu_frame_alias',

arguments=[

'0', '0', '0', # x, y, z

'0', '0', '0', # roll, pitch, yaw

'zed_camera_link',

'zed_imu_link'

],

parameters=[{'use_sim_time': False}], # CRITICAL FIX

)

# Bridge Rover Center (base_link) to Camera (The "Neck")

base_to_camera_fix = Node(

package='tf2_ros',

executable='static_transform_publisher',

name='base_to_camera',

arguments=[

'0.0', '0', '0.0', # x, y, z (REPLACE with actual offsets!)

'0', '0', '0', # roll, pitch, yaw

'base_link',

'zed_camera_link'

],

parameters=[{'use_sim_time': False}], # CRITICAL FIX

)

reddit.com
u/Any-Statement-4279 — 4 days ago
▲ 4 r/ROS

Laser scan moves and rotates with the robot in real life

Hello everyone,

I know this is the most asked question in any navigation robots, but I have been stuck for a long on this and I cant still figure out the problem. I have robot based on the Josh Newans diff drive navigation robot, I am using rasperry pi 4 with ros2 humble on both the pi and the dev machine. I am building the hardware and I am using rplidar c1. Everything in simulation works perfect, the mapping and localizing is okay, the ros2 controllers are loaded fine and the laser scan stays in it place when the robot moves away from it. However with the hardware, I cant do SLAM because the laser scan reading moves along with the robot whenever I moves or rotate it.

I read about all this (even 4 days ago someone asked the same question) and everyone said its an odometry and TF issue, but I tested the encoders and adjusted the robot's URDF to match with the real one, I did the following regarding the encoders and odometry:

  1. I rotated the wheels one full revolution and adjusted the encoder counts per revolution tag in the ros2 controllers xacro, now one full spin in real life is same in rviz2 with correct direction (clockwise and counter clockwise)
  2. I moved the robot one full meter in real life and adjusted the wheel radius until the motion is the same in the rviz2
  3. I rotated the robot in place and adjusted the separation distance until it synced.

The robot starts and the controllers are loaded successfully and the odom, tf and scan and static_tf are also published correctly, however in rviz2 when I switch the fixed frame to odom frame, the scan moves with the robot.

I dont know how to figure out this, Josh Newans actually mentioned this issue here as TF sync issue at 7:30 but he dismissed it as he doesn't know the solution and hoped that it worked for everyone else...

I feel like this is a problem that is hiding in the plain sight and I cant see, and its extremely annoying because I am stuck with this issue that I have to have it fix in order to proceed with my actual project, and I cant just solve for like three weeks now. I theorize that this issue is closely related to ros2_controller or the joint_state_broadcaster but I cant still fix it no matter I do or try, so please any help will be extremely beneficial.

This is the TF tree

https://preview.redd.it/eqxkzorbiq1h1.png?width=1574&format=png&auto=webp&s=28f1e73c06ebae4a08685ab7ece7ced18ec9ffb3

This is ros2_controller yaml file:

    update_rate: 30
    # use_sim_time: true

    diff_cont:
      type: diff_drive_controller/DiffDriveController

    joint_broad:
      type: joint_state_broadcaster/JointStateBroadcaster

diff_cont:
  ros__parameters:

    publish_rate: 30.0

    base_frame_id: base_link

    left_wheel_names: ['left_wheel_joint']
    right_wheel_names: ['right_wheel_joint']
    wheel_separation: 0.255
    wheel_radius: 0.033

    use_stamped_vel: false
    enable_odom_tf: true
    odom_frame_id: odom
    # open_loop: false    

    # wheels_per_side: x
    # wheel_separation_multiplier: x
    # left_wheel_radius_multiplier: x
    # right_wheel_radius_multiplier: x

    # odom_frame_id: x
    # pose_covariance_diagonal: x
    # twist_covariance_diagonal: x
    # open_loop: x
    # enable_odom_tf: x

    # cmd_vel_timeout: x
    # publish_limited_velocity: x
    # velocity_rolling_window_size: x
    

    # linear.x.has_velocity_limits: false
    # linear.x.has_acceleration_limits: false
    # linear.x.has_jerk_limits: false
    # linear.x.max_velocity: NAN
    # linear.x.min_velocity: NAN
    # linear.x.max_acceleration: NAN
    # linear.x.min_acceleration: NAN
    # linear.x.max_jerk: NAN
    # linear.x.min_jerk: NAN

    # angular.z.has_velocity_limits: false
    # angular.z.has_acceleration_limits: false
    # angular.z.has_jerk_limits: false
    # angular.z.max_velocity: NAN
    # angular.z.min_velocity: NAN
    # angular.z.max_acceleration: NAN
    # angular.z.min_acceleration: NAN
    # angular.z.max_jerk: NAN
    # angular.z.min_jerk: NAN




# joint_broad:
#   ros__parameters:
#     publish_rate: 30.0

This is the launch_robot.launch.py

import os

from ament_index_python.packages import get_package_share_directory


from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, TimerAction
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import Command
from launch.substitutions import LaunchConfiguration
from launch.actions import RegisterEventHandler
from launch.event_handlers import OnProcessStart

from launch_ros.actions import Node



def generate_launch_description():

    package_name='articubot_one' #<--- CHANGE ME
    lidar_package='rplidar_ros'

    lidar_serial_port = LaunchConfiguration('lidar_serial_port')
    lidar_serial_baudrate = LaunchConfiguration('lidar_serial_baudrate')
    lidar_frame_id = LaunchConfiguration('lidar_frame_id')

    declare_lidar_serial_port = DeclareLaunchArgument(
        'lidar_serial_port',
        default_value='/dev/ttyUSB1',
        description='Serial port used by RPLidar'
    )

    declare_lidar_serial_baudrate = DeclareLaunchArgument(
        'lidar_serial_baudrate',
        default_value='460800',
        description='Serial baudrate used by RPLidar'
    )

    declare_lidar_frame_id = DeclareLaunchArgument(
        'lidar_frame_id',
        default_value='laser_frame',
        description='TF frame_id used by /scan messages'
    )

    

    rsp = IncludeLaunchDescription(
                PythonLaunchDescriptionSource([os.path.join(
                    get_package_share_directory(package_name),'launch','rsp.launch.py'
                )]), launch_arguments={'use_sim_time': 'false', 'use_ros2_control': 'true'}.items()
    )

    camera = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([os.path.join(
            get_package_share_directory(package_name),'launch','camera.launch.py'
        )])
    )

    joystick = IncludeLaunchDescription(
                PythonLaunchDescriptionSource([os.path.join(
                    get_package_share_directory(package_name),'launch','joystick.launch.py'
                )])
    )

    lidar = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([os.path.join(
            get_package_share_directory(lidar_package), 'launch', 'rplidar_c1_launch.py'
        )]),
        launch_arguments={
            'serial_port': lidar_serial_port,
            'serial_baudrate': lidar_serial_baudrate,
            'frame_id': lidar_frame_id,
        }.items()
    )


    twist_mux_params = os.path.join(get_package_share_directory(package_name),'config','twist_mux.yaml')
    twist_mux = Node(
            package="twist_mux",
            executable="twist_mux",
            parameters=[twist_mux_params],
            remappings=[('/cmd_vel_out','/diff_cont/cmd_vel_unstamped')]
        )

    


    robot_description = Command(['ros2 param get --hide-type /robot_state_publisher robot_description'])

    controller_params_file = os.path.join(get_package_share_directory(package_name),'config','my_controllers.yaml')

    controller_manager = Node(
        package="controller_manager",
        executable="ros2_control_node",
        parameters=[{'robot_description': robot_description},
                    controller_params_file]
    )

    delayed_controller_manager = TimerAction(period=3.0, actions=[controller_manager])

    diff_drive_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["diff_cont"],
    )

    delayed_diff_drive_spawner = RegisterEventHandler(
        event_handler=OnProcessStart(
            target_action=controller_manager,
            on_start=[diff_drive_spawner],
        )
    )

    joint_broad_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["joint_broad"]
    )

    delayed_joint_broad_spawner = RegisterEventHandler(
        event_handler=OnProcessStart(
            target_action=controller_manager,
            on_start=[joint_broad_spawner],
        )
    )




    return LaunchDescription([
        declare_lidar_serial_port,
        declare_lidar_serial_baudrate,
        declare_lidar_frame_id,
        joystick,
        rsp,
        delayed_controller_manager,
        delayed_diff_drive_spawner,
        delayed_joint_broad_spawner,
        camera,

    ])

this is the rsp.launch.py

import os

from ament_index_python.packages import get_package_share_directory

from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration, Command
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node

import xacro


def generate_launch_description():

    # Check if we're told to use sim time
    use_sim_time = LaunchConfiguration('use_sim_time')
    use_ros2_control = LaunchConfiguration('use_ros2_control')

    # Process the URDF file
    pkg_path = os.path.join(get_package_share_directory('articubot_one'))
    xacro_file = os.path.join(pkg_path,'description','robot.urdf.xacro')
    # robot_description_config = xacro.process_file(xacro_file).toxml()
    robot_description_config = Command(['xacro ', xacro_file, ' use_ros2_control:=', use_ros2_control, ' sim_mode:=', use_sim_time])
    
    # Create a robot_state_publisher node
    params = {'robot_description': robot_description_config, 'use_sim_time': use_sim_time}
    node_robot_state_publisher = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        output='screen',
        parameters=[params]
    )


    # Launch!
    return LaunchDescription([
        DeclareLaunchArgument(
            'use_sim_time',
            default_value='false',
            description='Use sim time if true'),
        DeclareLaunchArgument(
            'use_ros2_control',
            default_value='true',
            description='Use ros2_control if true'),

        node_robot_state_publisher
    ])

This is the rplidar c1 launch file:

#!/usr/bin/env python3

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.actions import LogInfo
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node


def generate_launch_description():
    channel_type =  LaunchConfiguration('channel_type', default='serial')
    serial_port = LaunchConfiguration('serial_port', default='/dev/ttyUSB1')
    serial_baudrate = LaunchConfiguration('serial_baudrate', default='460800')
    frame_id = LaunchConfiguration('frame_id', default='laser_frame')
    inverted = LaunchConfiguration('inverted', default='false')
    angle_compensate = LaunchConfiguration('angle_compensate', default='true')
    scan_mode = LaunchConfiguration('scan_mode', default='Standard')

    return LaunchDescription([
        DeclareLaunchArgument(
            'channel_type',
            default_value=channel_type,
            description='Specifying channel type of lidar'),

        DeclareLaunchArgument(
            'serial_port',
            default_value=serial_port,
            description='Specifying usb port to connected lidar'),

        DeclareLaunchArgument(
            'serial_baudrate',
            default_value=serial_baudrate,
            description='Specifying usb port baudrate to connected lidar'),
        
        DeclareLaunchArgument(
            'frame_id',
            default_value=frame_id,
            description='Specifying frame_id of lidar'),

        DeclareLaunchArgument(
            'inverted',
            default_value=inverted,
            description='Specifying whether or not to invert scan data'),

        DeclareLaunchArgument(
            'angle_compensate',
            default_value=angle_compensate,
            description='Specifying whether or not to enable angle_compensate of scan data'),

        DeclareLaunchArgument(
            'scan_mode',
            default_value=scan_mode,
            description='Specifying scan mode of lidar'),

        Node(
            package='rplidar_ros',
            executable='rplidar_node',
            name='rplidar_node',
            parameters=[{'channel_type':channel_type,
                         'serial_port': serial_port,
                         'serial_baudrate': serial_baudrate,
                         'frame_id': frame_id,
                         'inverted': inverted,
                         'angle_compensate': angle_compensate,
                         'scan_mode': scan_mode}],
            output='screen'),
    ])

this is the ros2 controller xacro files

this is the ros_controller file 
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">

    <xacro:unless value="$(arg sim_mode)">
        <ros2_control name="RealRobot" type="system">
            <hardware>
                <plugin>diffdrive_arduino/DiffDriveArduinoHardware</plugin>
                <param name="left_wheel_name">left_wheel_joint</param>
                <param name="right_wheel_name">right_wheel_joint</param>
                <param name="loop_rate">30</param>
                <param name="device">/dev/ttyUSB0</param>
                <param name="baud_rate">57600</param>
                <param name="timeout_ms">1000</param>
                <param name="enc_counts_per_rev">1496</param>
            </hardware>
            <joint name="left_wheel_joint">
                <command_interface name="velocity">
                    <param name="min">-10</param>
                    <param name="max">10</param>
                </command_interface>
                <state_interface name="position"/>
                <state_interface name="velocity"/>
            </joint>
            <joint name="right_wheel_joint">
                <command_interface name="velocity">
                    <param name="min">-10</param>
                    <param name="max">10</param>
                </command_interface>
                <state_interface name="position"/>
                <state_interface name="velocity"/>
            </joint>
        </ros2_control>
    </xacro:unless>

    <xacro:if value="$(arg sim_mode)">
        <ros2_control name="GazeboSystem" type="system">
            <hardware>
                <plugin>gazebo_ros2_control/GazeboSystem</plugin>
            </hardware>
            <joint name="left_wheel_joint">
                <command_interface name="velocity">
                    <param name="min">-10</param>
                    <param name="max">10</param>
                </command_interface>
                <state_interface name="velocity"/>
                <state_interface name="position"/>
            </joint>
            <joint name="right_wheel_joint">
                <command_interface name="velocity">
                    <param name="min">-10</param>
                    <param name="max">10</param>
                </command_interface>
                <state_interface name="velocity"/>
                <state_interface name="position"/>
            </joint>
        </ros2_control>
    </xacro:if>

    <gazebo>
        <plugin name="gazebo_ros2_control" filename="libgazebo_ros2_control.so">
            <parameters>$(find articubot_one)/config/my_controllers.yaml</parameters>
            <parameters>$(find articubot_one)/config/gaz_ros2_ctl_use_sim.yaml</parameters>
        </plugin>
    </gazebo>

</robot>

The robot_core.xacro

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" >

    <xacro:include filename="inertial_macros.xacro"/>


    <xacro:property name="chassis_length" value="0.335"/>
    <xacro:property name="chassis_width" value="0.265"/>
    <xacro:property name="chassis_height" value="0.138"/>
    <xacro:property name="chassis_mass" value="1.0"/>
    <xacro:property name="wheel_radius" value="0.03125"/>
    <xacro:property name="wheel_thickness" value="0.026"/>
    <xacro:property name="wheel_mass" value="0.05"/>
    <xacro:property name="wheel_offset_x" value="0.026"/>
    <xacro:property name="wheel_offset_y" value="0.1485"/>
    <xacro:property name="wheel_offset_z" value="0.01"/>
    <xacro:property name="caster_wheel_radius" value="0.01"/>
    <xacro:property name="caster_wheel_mass" value="0.01"/>
    <xacro:property name="caster_wheel_offset_x" value="0.075"/>
    <xacro:property name="caster_wheel_offset_z" value="${wheel_offset_z - wheel_radius + caster_wheel_radius}"/>

    <material name="white">
        <color rgba="1 1 1 1" />
    </material>

    <material name="orange">
        <color rgba="1 0.3 0.1 1"/>
    </material>

    <material name="blue">
        <color rgba="0.2 0.2 1 1"/>
    </material>

    <material name="black">
        <color rgba="0 0 0 1"/>
    </material>

    <material name="red">
        <color rgba="1 0 0 1"/>
    </material>

    <!-- BASE LINK -->

    <link name="base_link">

    </link>

    <!-- BASE_FOOTPRINT LINK -->

    <joint name="base_footprint_joint" type="fixed">
        <parent link="base_link"/>
        <child link="base_footprint"/>
        <origin xyz="0 0 0" rpy="0 0 0"/>
    </joint>

    <link name="base_footprint">
    </link>


    <!-- CHASSIS LINK -->

    <joint name="chassis_joint" type="fixed">
        <parent link="base_link"/>
        <child link="chassis"/>
        <origin xyz="${-wheel_offset_x} 0 ${-wheel_offset_z}"/>
    </joint>

    <link name="chassis">
        <visual>
            <origin xyz="${chassis_length/2} 0 ${chassis_height/2}"/>
            <geometry>
                <box size="${chassis_length} ${chassis_width} ${chassis_height}"/>
            </geometry>
            <material name="orange"/>
        </visual>
        <collision>
            <origin xyz="${chassis_length/2} 0 ${chassis_height/2}"/>
            <geometry>
                <box size="${chassis_length} ${chassis_width} ${chassis_height}"/>
            </geometry>
        </collision>
        <xacro:inertial_box mass="0.5" x="${chassis_length}" y="${chassis_width}" z="${chassis_height}">
            <origin xyz="${chassis_length/2} 0 ${chassis_height/2}" rpy="0 0 0"/>
        </xacro:inertial_box>
    </link>

    <gazebo reference="chassis">
        <material>Gazebo/Orange</material>
    </gazebo>

    <!-- LEFT WHEEL LINK -->

    <joint name="left_wheel_joint" type="continuous">
        <parent link="base_link"/>
        <child link="left_wheel"/>
        <origin xyz="0 ${wheel_offset_y} 0" rpy="-${pi/2} 0 0" />
        <axis xyz="0 0 1"/>
    </joint>

    <link name="left_wheel">
        <visual>
            <geometry>
                <cylinder radius="${wheel_radius}" length="${wheel_thickness}"/>
            </geometry>
            <material name="blue"/>
        </visual>
        <collision>
            <geometry>
                <sphere radius="${wheel_radius}"/>
            </geometry>
        </collision>
        <xacro:inertial_cylinder mass="${wheel_mass}" length="${wheel_thickness}" radius="${wheel_radius}">
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </xacro:inertial_cylinder>
    </link>

    <gazebo reference="left_wheel">
        <material>Gazebo/Blue</material>
    </gazebo>




    <!-- RIGHT WHEEL LINK -->

    <joint name="right_wheel_joint" type="continuous">
        <parent link="base_link"/>
        <child link="right_wheel"/>
        <origin xyz="0 ${-wheel_offset_y} 0" rpy="${pi/2} 0 0" />
        <axis xyz="0 0 -1"/>
    </joint>

    <link name="right_wheel">
        <visual>
            <geometry>
                <cylinder radius="${wheel_radius}" length="${wheel_thickness}"/>
            </geometry>
            <material name="blue"/>
        </visual>
        <collision>
            <geometry>
                <sphere radius="${wheel_radius}"/>
            </geometry>
        </collision>
        <xacro:inertial_cylinder mass="${wheel_mass}" length="${wheel_thickness}" radius="${wheel_radius}">
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </xacro:inertial_cylinder>
    </link>

    <gazebo reference="right_wheel">
        <material>Gazebo/Blue</material>
    </gazebo>


    <!-- CASTER WHEEL LINK -->

    <joint name="caster_wheel_joint" type="fixed">
        <parent link="chassis"/>
        <child link="caster_wheel"/>
        <origin xyz="${caster_wheel_offset_x} 0 ${caster_wheel_offset_z}"/>
    </joint>


    <link name="caster_wheel">
        <visual>
            <geometry>
                <sphere radius="${caster_wheel_radius}"/>
            </geometry>
            <material name="white"/>
        </visual>
        <collision>
            <geometry>
                <sphere radius="${caster_wheel_radius}"/>
            </geometry>
        </collision>
        <xacro:inertial_sphere mass="${caster_wheel_mass}" radius="${caster_wheel_radius}">
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </xacro:inertial_sphere>
    </link>

    <gazebo reference="caster_wheel">
        <material>Gazebo/White</material>
        <mu1 value="0.001"/>
        <mu2 value="0.001"/>
    </gazebo>

</robot>

This is the lidar.xacro

<robot xmlns:xacro="http://www.ros.org/wiki/xacro" >

    <joint name="laser_joint" type="fixed">
        <parent link="chassis"/>
        <child link="laser_frame"/>
        <origin xyz="0.162 0 0.212" rpy="0 0 0"/>
    </joint>

    <link name="laser_frame">
        <visual>
            <geometry>
                <cylinder radius="0.05" length="0.04"/>
            </geometry>
            <material name="black"/>
        </visual>
        <visual>
            <origin xyz="0 0 -0.05"/>
            <geometry>
                <cylinder radius="0.01" length="0.1"/>
            </geometry>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <cylinder radius="0.05" length="0.04"/>
            </geometry>
        </collision>
        <xacro:inertial_cylinder mass="0.1" length="0.04" radius="0.05">
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </xacro:inertial_cylinder>
    </link>



    <gazebo reference="laser_frame">
        <material>Gazebo/Black</material>

        <sensor name="laser" type="ray">
            <pose> 0 0 0 0 0 0 </pose>
            <visualize>false</visualize>
            <update_rate>10</update_rate>
            <ray>
                <scan>
                    <horizontal>
                        <samples>360</samples>
                        <min_angle>-3.14</min_angle>
                        <max_angle>3.14</max_angle>
                    </horizontal>
                </scan>
                <range>
                    <min>0.3</min>
                    <max>12</max>
                </range>
            </ray>
            <plugin name="laser_controller" filename="libgazebo_ros_ray_sensor.so">
                <ros>
                    <argument>~/out:=scan</argument>
                </ros>
                <output_type>sensor_msgs/LaserScan</output_type>
                <frame_name>laser_frame</frame_name>
            </plugin>
        </sensor>
    </gazebo>

</robot><robot xmlns:xacro="http://www.ros.org/wiki/xacro" >

    <joint name="laser_joint" type="fixed">
        <parent link="chassis"/>
        <child link="laser_frame"/>
        <origin xyz="0.162 0 0.212" rpy="0 0 0"/>
    </joint>

    <link name="laser_frame">
        <visual>
            <geometry>
                <cylinder radius="0.05" length="0.04"/>
            </geometry>
            <material name="black"/>
        </visual>
        <visual>
            <origin xyz="0 0 -0.05"/>
            <geometry>
                <cylinder radius="0.01" length="0.1"/>
            </geometry>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <cylinder radius="0.05" length="0.04"/>
            </geometry>
        </collision>
        <xacro:inertial_cylinder mass="0.1" length="0.04" radius="0.05">
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </xacro:inertial_cylinder>
    </link>



    <gazebo reference="laser_frame">
        <material>Gazebo/Black</material>

        <sensor name="laser" type="ray">
            <pose> 0 0 0 0 0 0 </pose>
            <visualize>false</visualize>
            <update_rate>10</update_rate>
            <ray>
                <scan>
                    <horizontal>
                        <samples>360</samples>
                        <min_angle>-3.14</min_angle>
                        <max_angle>3.14</max_angle>
                    </horizontal>
                </scan>
                <range>
                    <min>0.3</min>
                    <max>12</max>
                </range>
            </ray>
            <plugin name="laser_controller" filename="libgazebo_ros_ray_sensor.so">
                <ros>
                    <argument>~/out:=scan</argument>
                </ros>
                <output_type>sensor_msgs/LaserScan</output_type>
                <frame_name>laser_frame</frame_name>
            </plugin>
        </sensor>
    </gazebo>

</robot>

moving the real robot moves the laser scan as well in rviz2

reddit.com
u/Complete_Astronaut_2 — 5 days ago
▲ 0 r/ROS

Installation of ROS Lyrical on Ubuntu 26.04

Hi,

I'm pretty new to ROS and I want to learn it. Due to this I have to setup my development environment. Since I heard that Ubuntu is the best platform and I want to start learning as smoothly as possible, I already installed Ubuntu 26.04.
Since Lyrical is the latest release of ROS and it officially supports Ubuntu 26.04, I'd like to install it, but there are no official installation instructions yet. I also heard, that the official Debian packages for Ubuntu 26.04 aren't stable yet and that some dependencies are missing.

Does anyone know how to run ROS on Ubuntu 26.04? What's the best way to install ROS on Ubuntu 26.04? - Especially for a beginner.

reddit.com
u/naibaf-1 — 6 days ago
▲ 76 r/ROS

Personal project: gripper and welder integrator hold_and_weld

Helloo people I built a dual-arm robotic welding workcell as a personal project. One arm holds the workpiece, the other welds.

Main components:

* Grasp sampler: constraint-aware antipodal grasp sampling on exact CAD surfaces via OCCT. Exclusion zones (weld seams, screw holes) and others are defined before sampling starts. Mesh support is planned.

* Weld planner: seam extraction from CAD (OCCT) and mesh (CGAL) geometry, outputs weld paths as JSON. Configurable.

* Application layer: lifecycle action servers, custom Ceres-based IK stack for seam approach validation, dual-arm coordinator. The kinematics stack is designed to eventually support pose finding for cleaner OMPL→Pilz handoff.

Still PoC stage but the full pipeline runs; STEP file to dual-arm execution in simulation. Roadmap and known limitations are in the repo.

Current weak points: the mesh pipeline in the weld planner is fragile; parameter sensitive and not validated on complex geometry yet, but I have found credible approaches in the literature to improve it.

The grasp sampler has a couple of minimal chokepoints that are straightforward to fix.

MoveIt's lack of lifecycle support required workarounds and concurrency handling still needs work. Visuals are also due an update (especially gripper).

Repo: https://github.com/silanus23/hold_and_weld

u/Latter-Doubt4354 — 7 days ago
▲ 64 r/ROS+1 crossposts

My experience using Claude Code for robotics from the advice of r/robotics

Hey r/robotics community,

A couple weeks back, I asked about how you all were managing AI development in robotics and I got a bunch of great responses. To summarize:

My problems

  • ROS 1 and ROS 2 commands/syntax, Gazebo versions, are consistently confused by Claude Code
  • Claude doesn't really understand the asynchronous messaging structure or any runtime-specific errors/bugs I may run into due to its code
  • The changes Claude Code makes during my development often lead my code in the wrong direction, making debugging take even longer

Your solutions

  • Many of you mentioned building custom tooling and skills really helps Claude orient itself
  • Supplying your own context and description of the repository and standardizing it across claude sessions using an `ARCHITECTURE.md` / `CLAUDE.md` also really helps
  • Minimal working examples are also very helpful. Having somewhere Claude can turn to and say, "this is a simple example of how things are supposed to work" helps the agent orient itself

I implemented four changes into my setup:

  1. Custom MCP tools and skills
  2. Supplying context from my own repository
  3. Supplying minimal working examples I made myself and found off the internet
  4. Supplying documentation relevant to my software stack. For me, that was ROS 2 Jazzy, Gazebo Harmonic, PX4, and Nav2

After making these changes, I've seen a pretty sizeable increase in my development speed using AI in robotics.

Previously, I was trying to fill my context window with the code I've already written, but that seemed to not be enough context for Claude to actually understand the software architecture or data pipeline in my codebase. With the changes I've mentioned above, I actually noticed that I can let Claude develop new nodes and software. There's significantly less problems when integrating Claude's code and existing code from what I've seen so far.

One thing that was always an annoyance for me was Claude's lack of understanding of what was ROS 1 and what was ROS 2. I ended up creating a RAG database that can input relevant documentation for whatever Claude was working on and that's worked incredibly well. With this in pairing with some custom tool calls I've made, my setup no longer has any confusion on what's ROS 2 and what commands I have access to running ROS 2 Jazzy and Gazebo Harmonic in particular.

Thanks for all of your help! I thought I'd leave this post here for those who may also run into something similar trying to use Claude Code for robotics. I'm considering even doing some custom evals for this setup on robotics-specific coding problems because of how much more consistent this setup seems to be. If anyone's already done something similar to this, would love to hear about it in the comments. Cheers!

reddit.com
u/Spare_Garden_755 — 9 days ago
▲ 11 r/ROS

ROS 2 Youtube Tutorials - poll

Hey guys, I saw some posts saing they want ROS 2 tutorials, also I got some feedback IRL from students, so I'm asking here too. What would you like to see most?

  • nav2 + lidar
  • ros2_control
  • Image processing (Yolo, segmentation, Pose, etc..)
  • Jazzy
  • Gazebo
  • Isaac Sim
  • LeRobot
  • Legged robots
  • multi robot
  • drones
  • other AI ( ASR, TTS, LLMs, agents ... )
  • ...

I already made some real robots with Jazzy so maybe adapting that to youtube videos & Gz simulation? Let me know, thanks!

u/martincerven — 8 days ago
▲ 6 r/ROS

ROS2 Motion Planning: MoveIt or Custom Solution?

Hello,

We are currently developing a new software stack for our pick-and-place robot because the existing system has become legacy, and we are considering using ROS 2 for the new platform.

I have a question for people who have built robots with ROS 2 in an industrial/company environment:

Did you develop your own motion planner, or did you rely on existing solutions such as MoveIt / MoveItCpp with planners like Pilz?

We have been experimenting with MoveIt and MoveItCpp, but trajectory generation seems relatively slow for our use case. It is possible that our implementation or configuration is not optimal, but we already tried to follow best practices as much as possible.

I would be interested to hear:

  • What architecture/planning stack you ended up using
  • Whether MoveIt was fast enough for production pick-and-place applications
  • If you switched to a custom planner, what were the main reasons

Thanks.

reddit.com
u/designer120 — 7 days ago
▲ 14 r/ROS

Nav2 goal failure.

Hi people,

I'm first time working with nav2, the robot fails to take sharp turns, what is the cause of this issue. How can i optimize the turning radiius.. taking wider turns.

u/An2s1 — 7 days ago
▲ 185 r/ROS+2 crossposts

Finished HW of my ROS 2 Bimanual diff drive robot

So far it has:

  • 2 Lerobot arms
  • Pan & Tilt with Realsense
  • Diff drive with ros2_control
  • Magnetic charging

Next I want to pick some clothes like socks and put them into washing machine autonomously 😄

u/martincerven — 11 days ago