Use the TF ROS 101 in your own project

So at the moment I’m trying the get the hang of this Transformation Frames. But I get very confused when I’m trying to apply it in my own project. I’m able to get data into RVIZ (which is allready a nice step) but they are completely of and also I get errors in RVIZ (sometimes RVIZ even crahses) so I’m doing something really wrong here. And I don;t know if it is because wrong URDF coding or wrong Python script for computing the odom and transformation.

I will post some snippet of my script here maybe someone sees here an error:

    def publish_tf(self):
            self.tf_broadcaster.sendTransform(
            (self.x, self.y, 0),  # Translation
            tf.transformations.quaternion_from_euler(0, 0, self.yaw),  # Rotation
            rospy.Time.now(),
            'base_link',
            'odom'
        )

    def calculate_odometry(self, right_vel_rpm, left_vel_rpm):
        wheelbase = 0.205                                                                                   # Wheelbase in m
        wheel_radius = 0.036                                                                                # Radius of wheel in m

        right_vel_mps = (2 * math.pi * wheel_radius * right_vel_rpm) / 60.0                                 # Convert rpm to m/s right side
        left_vel_mps = (2 * math.pi * wheel_radius * left_vel_rpm) / 60.0                                   # Convert rpm to m/s left side

        linear_velocity = (right_vel_mps + left_vel_mps) * 0.5                                              # Compute the linear velocity
        angular_velocity = (right_vel_mps - left_vel_mps) / wheelbase                                       # Compute angular velocity in rad/s

        current_time = rospy.Time.now()
        dt = (current_time - self.last_time).to_sec()                                                       # Compute integration time and covert from us to sec

        self.x += linear_velocity * math.cos(self.yaw) * dt
        self.y += linear_velocity * math.sin(self.yaw) * dt
        self.yaw += angular_velocity * dt

        self.publish_odom()
        self.publish_tf()


        self.last_time = current_time

    def publish_odom(self):
        odom = Odometry()
        odom.header.stamp = rospy.Time.now()
        odom.header.frame_id = 'odom'
        odom.child_frame_id = 'base_link'

        # Populate position
        odom.pose.pose.position.x = self.x
        odom.pose.pose.position.y = self.y
        odom.pose.pose.position.z = 0.0
        odom.pose.pose.orientation.z = math.sin(self.yaw / 2.0)
        odom.pose.pose.orientation.w = math.cos(self.yaw / 2.0)

        # Populate velocities
        odom.twist.twist.linear.x = 0.0
        odom.twist.twist.linear.y = 0.0
        odom.twist.twist.angular.z = 0.0

        self.pub_odom.publish(odom)

Above are the three main functions for publishing and computing odometry and the transformation. I compute velocities in the function calculate_odometry and call in that function the function to publish the transformation publish_tf, which is base_link to odom.

Now my frames.pdf looks as follows:

The errors in RVIZ tell me there is no transform from base_footprint to base_link. But hat I don’t understand where should I do this transform and why?

Also the tree in RVIZ looks different as the frames.pdf:
image

So I’m really confused, should I look for the error in my URDF/XACRO file or is my coding wrong?

My odom frame is completely off from my base_link

image

Thanks in advance

I fixed my issue partly, after looking around I have added a transfor from base_link to base_footprint and i have set the Fixed Frame setting to Odom.
Now this will show the robot moving around. But I got now errors with the robot_description because there are no transforms there. So it seemds like I can’t show the robot-description moving around or I need to make somewhere another transformation I guess.
All sensors, wheel frames etc are showing now errors

HI,

Could you share the code your are using, in a git or better in a ROsject? That way we can debug this a but further.

Also post these new error you are getting with this fix.

Issues with TFs related to:

  • URDF/XACRO: Normally they come because ethr control is not well setup . It can also happen if the URDF is not well connected bu then it would give errors stating that.

Hi Duckfrost2, thank you for replying to my question. I was able to upload my project to my GitHub acount. I haven’t created a Rosject by myself yet but I will have a look on how to do this.

But hopefully this gives all the information you need. So basically there all still two issue and I suspect indeed the XACRO/URDF.
First the vizualization of the robot is not correct and I got all those transform errors. Secondly when I drive the bot the distance is only half of the actual distance The last seems like an issue related to radius or diamaeter or so, a factor of exactly 2 is too much of a coincedence IMHO. But I haven’t found the issue yet and will keep looking for it when I have time.

Here is the link to my ROS package:

R2G2 Source Code

Thanks in advance

Ray

Hi,
I created this rosject so that you can develop it and debug it in a standard middle ground for everyone: https://app.theconstructsim.com/l/5b68bbaf/

It seems there is no simulationso I imagine that if I don’t have the robot its quite difficult to debug from my side.

Doe this work in simulation?

Normally if the robot model tf doesn’t appear ( probably because there is NO tranfrom from the odom frame to the base_footprint ) , the RVIZ doesn’t show it. Have you checked the tf tree? Is the odometry control working, publishing odometry topic info?

I launch this:

pip install serial
roslaunch r2g2 r2g2.launch

And get this error:

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to ‘/tmp/runtime-user’
[ERROR] [1693906554.443919723]: Ignoring transform for child_frame_id “100” from authority “unknown_publisher” because of an invalid quaternion in the transform (0.000000 0.000000 0.000000 0.000000)
Traceback (most recent call last):
File “/home/user/simulation_ws/devel/lib/rosserial_python/serial_node.py”, line 15, in
exec(compile(fh.read(), python_script, ‘exec’), context)
File “/home/user/simulation_ws/src/rosserial/rosserial_python/nodes/serial_node.py”, line 39, in
from rosserial_python import SerialClient, RosSerialServer
File “/home/user/simulation_ws/devel/lib/python3/dist-packages/rosserial_python/init.py”, line 34, in
exec(__fh.read())
File “”, line 1, in
File “/home/user/simulation_ws/src/rosserial/rosserial_python/src/rosserial_python/SerialClient.py”, line 48, in
from serial import Serial, SerialException, SerialTimeoutException
ImportError: cannot import name ‘Serial’ from ‘serial’ (/home/user/.local/lib/python3.8/site-packages/serial/init.py)
Traceback (most recent call last):
File “/home/user/simulation_ws/devel/lib/rosserial_python/serial_node.py”, line 15, in
exec(compile(fh.read(), python_script, ‘exec’), context)
File “/home/user/simulation_ws/src/rosserial/rosserial_python/nodes/serial_node.py”, line 39, in
from rosserial_python import SerialClient, RosSerialServer
File “/home/user/simulation_ws/devel/lib/python3/dist-packages/rosserial_python/init.py”, line 34, in
exec(__fh.read())
File “”, line 1, in
File “/home/user/simulation_ws/src/rosserial/rosserial_python/src/rosserial_python/SerialClient.py”, line 48, in
from serial import Serial, SerialException, SerialTimeoutException
ImportError: cannot import name ‘Serial’ from ‘serial’ (/home/user/.local/lib/python3.8/site-packages/serial/init.py)
[rosserial_python0-2] process has died [pid 9177, exit code 1, cmd /home/user/simulation_ws/devel/lib/rosserial_python/serial_node.py __name:=rosserial_python0 __log:=/home/user/.ros/log/9a0be1ea-4bcf-11ee-939c-0242c0a84007/rosserial_python0-2.log].
log file: /home/user/.ros/log/9a0be1ea-4bcf-11ee-939c-0242c0a84007/rosserial_python0-2*.log
[rosserial_python1-3] process has died [pid 9178, exit code 1, cmd /home/user/simulation_ws/devel/lib/rosserial_python/serial_node.py __name:=rosserial_python1 __log:=/home/user/.ros/log/9a0be1ea-4bcf-11ee-939c-0242c0a84007/rosserial_python1-3.log].
log file: /home/user/.ros/log/9a0be1ea-4bcf-11ee-939c-0242c0a84007/rosserial_python1-3*.log

Please need some info , debug form your part. Again probably is the TF tree that its not connected or the publisher of odom to base_link is not doing anything, but we need to check.

Hi,

First thanks for the fast response and time to help me, I really appreaciate!

I do not use any simulation because I’m bussy building a robot in real life ;). But the urdf shows very basically how it looks like.

I use rosserial to control the motors and read sensor data, but I assume that wont work if one want to do a simmulation (I’m not sure though).

The only transformations I did so far are these two:

    def publish_tf(self):
            self.tf_broadcaster.sendTransform(
            (self.x, self.y, 0),  # Translation
            tf.transformations.quaternion_from_euler(0, 0, self.yaw),  # Rotation
            rospy.Time.now(),
            'base_link',
            'odom'
        )
            
            # Add transformation from base_footprint to base_link
            self.tf_broadcaster.sendTransform(
            (0, 0, 0),  # No translation offset between base_footprint and base_link
            (0, 0, 0, 1),  # No rotation offset (identity quaternion)
            rospy.Time.now(),
            'base_link',
            'base_footprint'
        )

So reading your message I probably need to make another transform?

Here I did a rostopic echo /odom (left terminal) and a rostopic echo right_speed (left terminal nit is rpm).

The rpm is converted in the calculate odometry method.

If I use in RVIZ for fixed frame Base_link I get the same ppicture as you but when I add TF and change the fixed frame to odom errors appear.

Another weird thing is that if you look to the eft terminal and the values of the pose that can’t be correct it tells that it is 3452 m away from the centre. But I’m 100% sure that the conversion of rpm to m/s is correct.

But I think first fix this TF. Regarding those error I don’t know were to find these issues and how to solve them. For example this “Frame id 100” I don’t see anywhere.

Wait a minute I think this frame id is wrong here, must be a typo.

 <node name="robot_tf_publisher" pkg="tf2_ros" type="static_transform_publisher" args="0 0 0 0 0 0 world base_link 100" />

Here is also a image of the TF_frames

This might help cause I start to think here is somewhere the issue.

Ok well I have added the odom to base_footprint transform. Now I get a bit closer to where I want to be

What happens now is that when I let the robot drive with a joystick I see in RVIZ values published and with the echo also values that are acceptable more or less. But at the moment velocity is zero all goes back to the origin. I see also that there is no odom published anymore. In other words the odometry is only published when the motors are running.
This is a coding issue for sure but I do not know what would be the best strategy to solve this. Should I create a seperate script that publishes the odometry. So I have one script that calculates the odmetry and another for publishing…I dont know.

No one for further ideas to check? Although I’m travelling again I can’t fix it right now but ideas are more than welcome.

@duckfrost2 did I give decent troubleshoot info or wasn’t it sufficient?

Br

Sorry for the late reply:

  1. In the odom tree it strange because the ocom to base_footprint goes in the opposite direction. The publish should be from ’ odom’ to ’ base_foootprint’ .

  2. Normally in real systems, you have a driver that published the odometry message data, an then another rosnode that takes that odometry and published the TFs based on that data. That would be the way to go.

  3. As for the issue that only publishes when moving is really weird, unless you are getting the odometry changes instead of the global position, which is sometimes what happens. SOme odometry only give info of the delta in space, but don’t accumulate it or correct it, so you need to manage that. I would first test that you have a publisher of TF that publishes coherent TF ocom to basefootprint

@duckfrost2

Thanks for your reply no worries it took a while :wink:

As you can see im learning here. So I see I might have done some things wrong here.

The transform is firstly the wrong direction…ok clear.

Secondly I should seprate all this code in two parts. One the odom computation I receive the speeds in rpm and should comoute it to velocities m/s and distances in the time interval. Than publish this and create a second script for the transformations?

That means my whole strategy for this subject was wrong.

Please note I do not use cmd_vel etc. I compute the speed from my encoders convert this to m/s. And that do an integration to get the distance traveled in the timeinterval.
If I publish this to another script the transformation should go better. Offcourse if I do the transformation in the correct direction.

It is all still a bit new for me Im still new to ROS and learning a lot. Thanks for your explanation.
I not sure if I can.post later if all works fine cause this topic will be closed when I’m back home.

Br

To be honest what confuses me in my code is the difference between base_footprint and base_link.
Which one is the World? Because that is my main reference is I understand right. And Odom need to be transferred to the World.
But how this translates to the position of the robot is confusing me.

HI,

So it is as follows:

  1. In navigation ONLY using odometry, odom frame and world are the same thing.
  2. When we use navigation with slam, lasers and so on, what we do is that we adjust the errros made by the odometry of the encoder wheels, changing the tranfrom between world and odom. So odom to base_footprint is made by the wheel encoders and world to odom is made by the navigation laser system.

As for base_link and base_fottprint, the only main difference is that the footprint is the planar projection of the baseline, used for navigation mainly.

Now its getting more confusing for me. But interesting I’m learning stuff here.

What I have tried in my original code is as follows.

I use the encoders to compute the velocity. With the velocity I can compute the distance travelled and orientation (done with the difference of the two velocities of the wheels).
These values I tried to publish as a /odom topic. Than I expected that with using RVIZ and driving the robot in my room Inwould see in RVIZ the robot moving.

I do not use (yet) laser or a lidar or any such thing. So I wont expect it to be accurate but at least it should show the robot moving…or am I completely wrong?

Later I want to use some laser and IMU to make all more accurate.

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