[URDF ROS2 Turtlebot] Moving to real robot

Hello @bayodesegun @girishkumar.kannan
For URDF ROS2 section 6, i started moving the urdf to real robot. My first step in that direction was to replace the gazebo launch with turtlebot_* packages starting with bring up.

Is this the right place to start the split and then adjust urdf not to load laser scanners ?

Also, i have an issue with both directly launch and generate_launch_descripton () to do this step
Can you please provide some guidance here ?

  1. Direct launch with reference below gives tty error
    TurtleBot3

Failed to open the port(/dev/ttyACM0)!

user:~$ ros2 launch turtlebot3_bringup robot.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2025-02-01-06-11-37-859586-4_xterm-3625
[INFO] [launch]: Default logging verbosity is set to INFO
urdf_file_name : turtlebot3_burger.urdf
[INFO] [robot_state_publisher-1]: process started with pid [3626]
[INFO] [hlds_laser_publisher-2]: process started with pid [3628]
[INFO] [turtlebot3_ros-3]: process started with pid [3630]
[hlds_laser_publisher-2] 1738390297.978100 [0] hlds_laser: config: //CycloneDDS/Domain/General: 'NetworkInterfaceAddress': deprecated element (file:///var/lib/theconstruct.rrl/cyclonedds.xml line 5)
[turtlebot3_ros-3] 1738390297.978529 [0] turtlebot3: config: //CycloneDDS/Domain/General: 'NetworkInterfaceAddress': deprecated element (file:///var/lib/theconstruct.rrl/cyclonedds.xml line 5)
[hlds_laser_publisher-2] 1738390297.978981 [0] hlds_laser: add_peer_addresses: 4_xterm: unknown address
[hlds_laser_publisher-2] 1738390297.978981 [0] hlds_laser: add_peer_addresses: 4_xterm: unknown address
[turtlebot3_ros-3] 1738390297.979217 [0] turtlebot3: add_peer_addresses: 4_xterm: unknown address
[turtlebot3_ros-3] 1738390297.979217 [0] turtlebot3: add_peer_addresses: 4_xterm: unknown address
[robot_state_publisher-1] 1738390297.981036 [0] robot_stat: config: //CycloneDDS/Domain/General: 'NetworkInterfaceAddress': deprecated element (file:///var/lib/theconstruct.rrl/cyclonedds.xml line 5)
[robot_state_publisher-1] 1738390297.981876 [0] robot_stat: add_peer_addresses: 4_xterm: unknown address
[robot_state_publisher-1] 1738390297.981876 [0] robot_stat: add_peer_addresses: 4_xterm: unknown address
[hlds_laser_publisher-2] [INFO] [1738390297.985000387] [hlds_laser_publisher]: Init hlds_laser_publisher Node Main
[hlds_laser_publisher-2] [INFO] [1738390297.985083290] [hlds_laser_publisher]: port : /dev/ttyUSB0 frame_id : base_scan
[turtlebot3_ros-3] [INFO] [1738390297.988471242] [turtlebot3_node]: Init TurtleBot3 Node Main
[turtlebot3_ros-3] [INFO] [1738390297.988548405] [turtlebot3_node]: Init DynamixelSDKWrapper
[turtlebot3_ros-3] [ERROR] [1738390297.988578954] [DynamixelSDKWrapper]: Failed to open the port(/dev/ttyACM0)!
[turtlebot3_ros-3] [ERROR] [1738390297.988585082] [DynamixelSDKWrapper]: Failed to initialize SDK handlers
[turtlebot3_ros-3] [ERROR] [1738390297.988596669] [turtlebot3_node]: Failed connection with Devices
[turtlebot3_ros-3] [PortHandlerLinux::SetupPort] Error opening serial port!
[turtlebot3_ros-3] [INFO] [1738390297.989799758] [turtlebot3_node]: Add Motors
[turtlebot3_ros-3] [INFO] [1738390297.989842756] [turtlebot3_node]: Add Wheels
[turtlebot3_ros-3] [INFO] [1738390297.989907601] [turtlebot3_node]: Add Sensors
[turtlebot3_ros-3] terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
[turtlebot3_ros-3]   what():  could not create publisher: rcl node's context is invalid, at ./src/rcl/node.c:428
[robot_state_publisher-1] [INFO] [1738390298.030035842] [robot_state_publisher]: got segment base_footprint
[robot_state_publisher-1] [INFO] [1738390298.030116377] [robot_state_publisher]: got segment base_link
[robot_state_publisher-1] [INFO] [1738390298.030128724] [robot_state_publisher]: got segment base_scan
[robot_state_publisher-1] [INFO] [1738390298.030137156] [robot_state_publisher]: got segment caster_back_link
[robot_state_publisher-1] [INFO] [1738390298.030145075] [robot_state_publisher]: got segment imu_link
[robot_state_publisher-1] [INFO] [1738390298.030152901] [robot_state_publisher]: got segment wheel_left_link
[robot_state_publisher-1] [INFO] [1738390298.030161637] [robot_state_publisher]: got segment wheel_right_link
[ERROR] [turtlebot3_ros-3]: process has died [pid 3630, exit code -6, cmd '/opt/ros/humble/lib/turtlebot3_node/turtlebot3_ros -i /dev/ttyACM0 --ros-args --params-file /opt/ros/humble/share/turtlebot3_bringup/param/burger.yaml'].
[ERROR] [hlds_laser_publisher-2]: process has died [pid 3628, exit code 255, cmd '/opt/ros/humble/lib/hls_lfcd_lds_driver/hlds_laser_publisher --ros-args -r __node:=hlds_laser_publisher --params-file /tmp/launch_params_czd0cux0'].
  1. Generate launch description.
def generate_launch_description():
    os.environ['TURTLEBOT3_MODEL'] = 'burger'
    os.environ['LDS_MODEL'] = ""
    
    # Start the TurtleBot3 hardware drivers
    turtlebot3_node = Node(
        package='turtlebot3_bringup',
        executable='robot.launch.py',
        output='screen',
        parameters=[{
            'use_sim_time': False
        }]
    )

GIves error below.

[INFO] [launch]: All log files can be found below /home/user/.ros/log/2025-02-01-06-20-52-248573-4_xterm-5809
[INFO] [launch]: Default logging verbosity is set to INFO
Fetching URDF ==>
Fetching URDF ==>
Fetching URDF ==>
[ERROR] [launch]: Caught exception in launch (see debug for traceback): package 'turtlebot3_bringup' found at '/opt/ros/humble', but libexec directory '/opt/ros/humble/lib/turtlebot3_bringup' does not exist
[INFO] [robot_state_publisher-1]: process started with pid [5827]

Thanks,
Venkat

Good Morning. can you please check and assist on this query ?

Hi @vadhrivenkat ,

I think restarting the simulation or this process would fix this issue.

If you are launching the bringup command for the first time in a terminal, it could fail because some processes need some “warm-up” time to write stuff in to memory.

So, restarting the simulation and/or the this process should fix this issue.

The second error also indicates that the turtlebot3_bringup package dos not exist, which means you have not sourced the proper ROS2 workspace in the terminal in which you are launching the bringup process.

Regards,
Girish

Thanks @girishkumar.kannan for the reply.
I am doing fine on the simulation (see below). Its real robot, i could use some guidance.

I have double checked on the environment settings, seem fine to me.
I am connected to the real bot when i took this log ( few mins ago ! )

user:~/ros2_ws$ source install/setup.bash
user:~/ros2_ws$ source /opt/ros/humble/setup.bash
user:~/ros2_ws$ ros2 launch turtlebot3_bringup robot.launch.py
[INFO] [launch]: All log files can be found below /home/user/.ros/log/2025-02-04-05-12-26-924642-1_xterm-4004
[INFO] [launch]: Default logging verbosity is set to INFO
urdf_file_name : turtlebot3_burger.urdf
[INFO] [robot_state_publisher-1]: process started with pid [4021]
[INFO] [hlds_laser_publisher-2]: process started with pid [4023]
[INFO] [turtlebot3_ros-3]: process started with pid [4025]
[robot_state_publisher-1] 1738645947.108682 [0] robot_stat: config: //CycloneDDS/Domain/General: 'NetworkInterfaceAddress': deprecated element (file:///var/lib/theconstruct.rrl/cyclonedds.xml line 5)
[robot_state_publisher-1] 1738645947.109634 [0] robot_stat: add_peer_addresses: 1_xterm: unknown address
[robot_state_publisher-1] 1738645947.109634 [0] robot_stat: add_peer_addresses: 1_xterm: unknown address
[hlds_laser_publisher-2] 1738645947.109707 [0] hlds_laser: config: //CycloneDDS/Domain/General: 'NetworkInterfaceAddress': deprecated element (file:///var/lib/theconstruct.rrl/cyclonedds.xml line 5)
[hlds_laser_publisher-2] 1738645947.110532 [0] hlds_laser: add_peer_addresses: 1_xterm: unknown address
[hlds_laser_publisher-2] 1738645947.110532 [0] hlds_laser: add_peer_addresses: 1_xterm: unknown address
[turtlebot3_ros-3] 1738645947.111432 [0] turtlebot3: config: //CycloneDDS/Domain/General: 'NetworkInterfaceAddress': deprecated element (file:///var/lib/theconstruct.rrl/cyclonedds.xml line 5)
[turtlebot3_ros-3] 1738645947.112893 [0] turtlebot3: add_peer_addresses: 1_xterm: unknown address
[turtlebot3_ros-3] 1738645947.112893 [0] turtlebot3: add_peer_addresses: 1_xterm: unknown address
[hlds_laser_publisher-2] [INFO] [1738645947.118962093] [hlds_laser_publisher]: Init hlds_laser_publisher Node Main
[hlds_laser_publisher-2] [INFO] [1738645947.119491322] [hlds_laser_publisher]: port : /dev/ttyUSB0 frame_id : base_scan
[turtlebot3_ros-3] [INFO] [1738645947.121293906] [turtlebot3_node]: Init TurtleBot3 Node Main
[turtlebot3_ros-3] [INFO] [1738645947.121406236] [turtlebot3_node]: Init DynamixelSDKWrapper
[turtlebot3_ros-3] [ERROR] [1738645947.121486280] [DynamixelSDKWrapper]: Failed to open the port(/dev/ttyACM0)!
[turtlebot3_ros-3] [ERROR] [1738645947.121515600] [DynamixelSDKWrapper]: Failed to initialize SDK handlers
[turtlebot3_ros-3] [ERROR] [1738645947.121572431] [turtlebot3_node]: Failed connection with Devices
[turtlebot3_ros-3] [PortHandlerLinux::SetupPort] Error opening serial port!
[turtlebot3_ros-3] [INFO] [1738645947.142704195] [turtlebot3_node]: Add Motors
[turtlebot3_ros-3] [INFO] [1738645947.142786807] [turtlebot3_node]: Add Wheels
[turtlebot3_ros-3] [INFO] [1738645947.142803636] [turtlebot3_node]: Add Sensors
[turtlebot3_ros-3] terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
[turtlebot3_ros-3]   what():  could not create publisher: rcl node's context is invalid, at ./src/rcl/node.c:428
[robot_state_publisher-1] [INFO] [1738645947.193920283] [robot_state_publisher]: got segment base_footprint
[robot_state_publisher-1] [INFO] [1738645947.194032452] [robot_state_publisher]: got segment base_link
[robot_state_publisher-1] [INFO] [1738645947.194050580] [robot_state_publisher]: got segment base_scan
[robot_state_publisher-1] [INFO] [1738645947.194061702] [robot_state_publisher]: got segment caster_back_link
[robot_state_publisher-1] [INFO] [1738645947.194215306] [robot_state_publisher]: got segment imu_link
[robot_state_publisher-1] [INFO] [1738645947.194233323] [robot_state_publisher]: got segment wheel_left_link
[robot_state_publisher-1] [INFO] [1738645947.194245759] [robot_state_publisher]: got segment wheel_right_link
[ERROR] [hlds_laser_publisher-2]: process has died [pid 4023, exit code 255, cmd '/opt/ros/latest/lib/hls_lfcd_lds_driver/hlds_laser_publisher --ros-args -r __node:=hlds_laser_publisher --params-file /tmp/launch_params_rorg926f'].
[ERROR] [turtlebot3_ros-3]: process has died [pid 4025, exit code -6, cmd '/opt/ros/latest/lib/turtlebot3_node/turtlebot3_ros -i /dev/ttyACM0 --ros-args --params-file /opt/ros/latest/share/turtlebot3_bringup/param/burger.yaml'].
^C[WARNING] [launch]: user interrupted with ctrl-c (SIGINT)
[robot_state_publisher-1] [INFO] [1738645961.528783564] [rclcpp]: signal_handler(signum=2)
[INFO] [robot_state_publisher-1]: process has finished cleanly [pid 4021]
user:~/ros2_ws$

Can you please point me to some docs or links which can help understand the urdf movment to real robot ?

Hi @vadhrivenkat ,

I think you are over-engineering the task required to complete the URDF Real Robot project.

Can you post the contents of your turtlebot3_bringup launch file?
I think you are inadvertently implementing something that is not actually a part of the real robot itself.

I have never seen the hlds_laser_publisher node when I worked on the real robot TurtleBot3 in The Construct’s labs.

Could you first please clarify if you are following the rosject instructions correctly and not over-doing stuff?

Regards,
Girish

Yep!, i see the only following instructions in the rosject for moving to real robot.

In the list below, i can connect to the real robot and used telop which moves the robot and there are no errors atlest on the console. i commented to gazebo ros2 control in urdf.

There is not much in there to deduce the changes required for urdf files.
please point me to the part of the rosjet docs that could shine some light on that.

Test your Robot Model on the Real Robot 
Once your robot is working 100% in the simulation, then it is time to test your package on the real robot.

Follow the steps to test your work on the real robot:

Book a date and time in the Real Robot Lab (refer Appendix below).
On the date and time selected, open this rosject.
Connect to the real robot lab from within this rosject (refer Appendix below).
You can use the on-screen joystick that is displayed along with the camera streams to move the real robot.
You don't need to launch the simulation, because you are using the real thing!
Launch your program(s) to see if the robot responds to the teleop commands. Chances are it will not - because the simulation is not exactly same as the real robot. Debug your package again to find the reason and fix it.
Now, this is your chance to get to know the real robot, even more than you knew! Use all the tools that you learned in the ROS2 courses to check the properties of the real robot, such as Topics, TF Tree, TF Echo, etc.
Keep testing on the real robot until you have fixed all the errors and you have everything working as expected.
Create a new URDF file specifically for the real robot. Name the file as tb3_burger_real.urdf, so you can make changes to this file without modifying the original tb3_burger.urdf file.

The only other information on moving the real hw were in the next section.

If you have successfully completed Part 2, and tested your work on the real robot, you might have noticed a few things:

You cannot implement the Lidar Spin Controller, because the Lidar spins automatically on the real robot.
The TF Tree is a bit different from what you have from the URDF file that you created.

At the moment, i am trying to use a spawn robot file that is moved from gazebo ros to turtlebot as below.

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import random

from launch_ros.actions import Node
import os
from ament_index_python.packages import get_package_prefix
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

# this is the function launch  system will look for
def generate_launch_description():
    os.environ['TURTLEBOT3_MODEL'] = 'burger'
    os.environ['LDS_MODEL'] = ""
    
    # Start the TurtleBot3 hardware drivers
    turtlebot3_node = Node(
        package='turtlebot3_node',
        executable='turtlebot3_ros',
        output='screen',
        parameters=[{
            'use_sim_time': False
        }]
    )

    # create and return launch description object
    return LaunchDescription(
        [
            turtlebot3_node,
        ]
    )

Hi @vadhrivenkat ,

Yes, teleop (not telop) should definitely work fine on the real robot TurtleBot3.

Yes, you cannot use gazebo related things when working with the real robot as it is not a simulation!

This is the line that is shining you the “light” and for you to absorb the “light” you need to know how to work with TF tools in ROS2! [Seriously, this is all the “light” you need!]
To simply put, for the robot that you created, the link positions are what you defined in your URDF file (which is with respect to the base_link).
When it comes to the real robot, the position information for the links are already fixed. You can either access the /tf topic or use the tf2_tools and tf2_echo commands to find the position of the links with respect to the base_link of the robot. From that information, you can modify your URDF file that you created for the simulation and adapt it to the real robot.

Yes, the Lidar Spin Controller is an obvious thing because we are “mimicking” a lidar spin motion in the simulation, whereas on the real robot, a motor takes care of that, and you can’t control that motor (the motor is pre-programmed to run at fixed rate).
The TF-tree is different from your simulation robot because the link names and their positions cannot be changed! They are permanent. So for you to adapt that TF-tree onto your URDF file, you need to modify the link names and positions to what is present on the real robot.

You can never spawn anything in the real robot situation. Please use appropriate terminology!
I don’t know what the turtlebot3_ros node does in the launch file content that you shared.

The task for you in the whole project is to just make use of the TF tree that is present in the real robot and augment that with any other robot links and joints that you have created.
You do not need to start any hardware or initialize any hardware on the real robot. Everything is already setup and running, for example, camera, lidar, motor controller, etc.
You just need to use the TF tree that is on the real robot and use the topics like cmd_vel, imu, odom, lidar, etc to make the robot perform some basic movement around the arena.

I have given you all the information that you will require!

Regards,
Girish

Very detailed, thank you for your time ! :slightly_smiling_face:

Hi @vadhrivenkat ,

You’re welcome!

Please let me know if you got everything working on the real robot!

Regards,
Girish

Good morning. I seem to have good progress on the real robot after making some changes for merging the TF tree but i dont have the camera from the real robot.

I digged a bit and realized that the camera is not part of the original HW TF tree.
I am missing something. can you please let me know how can i make this look like the TF tree on the rosjet ?

TF Tree

Hi @vadhrivenkat ,

You have an issue with your laser scan which is evident from your image. You need to set use_sim_time variable to False when working on the real robot to avoid this weird duplication of laser scan visuals.

Yes the camera is finicky. Sometimes it works, sometimes it does not. Don’t worry much if that does not work.

You need to figure that out, as to how to merge the TF tree of the real robot with your URDF links and joints. This is your task in Part 3. Even the slightest hint that we give you will become the solution! So try to find an intuitive engineering solution!

Also, the word for the rosject environment is ROSject, ROS + project = rosject. It is not rosjet (not ROS + :airplane: )!

Regards,
Girish

I merged the tf trees, what i mean in the question is how to get the camera into tf tree.
Is this okay that i have a slightly different structure ?

There were two residues in the simulation from the /odom and /scan. /odom i adjusted with how much history to keep and set sim_time to False for the real robot… However i did not find such a config for /scan. I will try more and keep this thread posted after finishing part 3.

Thanks,
Venkat

Hi @vadhrivenkat ,

Simple, if there is no camera link in the real robot then you cannot have a camera!
So forget about the camera, or add a enable/disable xacro argument to the camera link in your URDF that you made for the real robot. On the day of live presentation, if the camera link is available, then enable the camera otherwise have it disabled in the urdf/xacro file.

Both the images you posted are not helpful.
The first image was too blurry, so I could not zoom in.
The second picture is cut off. So I can’t make out anything from a part TF-tree.
Please re-post the TF-tree image properly.

The use_sim_time variable is NOT topic specific for /odom. The variable is ROS2 node parameter, so it applies to any node you set it to in the launch file node declaration. The variable applies to the whole ros2 node, so not specific to a single topic!

QoS History policy of a topic has nothing to do with use_sim_time variable (node parameter).

Sure!

Regards,
Girish