Convert encoder data to nav_msgs/odometery

I want to ask a really important question now i built a 4w mobile robot but i want to convert data from the encoder so i can publish it on the odom topic what are the equations to do so

I’ll try to give you a strategy on how to do this but because we don’t know what type of hardware you use I can’t be specific with the answer.

Basically you would first to convert the pulses to a CPS value (Cycles Per Second). You could do this in two ways.

  1. Compute the time between two pulses and than multiply it with the amount of pulses per rotation (this depends on what type of encoder you use).

  2. Define a time interval (e.g. 1 sec) and count the amount of pulses during this interval. This number you devide by the amount of pulses per rotation.

Now you know how many rotations per second your motor rotates. Next step is to convert this to a value in m/s. This is quite easy if you measure the diameter of your wheels and multiply it by PI:

circumference = PI * d

Becarefull if you want the speed in m/s you have to put the diamater in the equation in meters as well.

So now you know the rotation speed in in CPR and you know the circumference in meters, all you have to do now is muliply the both with eachother:

v = CPR * Circumference = m/s

I hope this helps you a bit, good luck

I actually did just as you said but the odometery message should consist of postiton in X,y,z and also an the orientation pf the robot in x,y,z,w which the procedure you said just calculate the position and velocity in x
I am using 4w with hall effect encoder (magnetic encoder) i will not use stearing means in order to turn the wheels on the left will rotate in different direction than the right wheel

It is not calculating the position it is calculating the speed of a wheel on your robot which is a linear velocity.

I dont know how you have written the code but to do this accurate you will have to work with interrupts in your code. Also make the time delay much shorter as 1 sec as I wrote in my previous post, that was just an arbitrary value

ps If you want to compute the new position you will have to multiply the speed by the the time it was moving.

s = v * t

This is just some standard physics, I’m still learning ROS so I’m not a specialist in ROS. But if you know how long the motors are running and you know the speed you can compute the distance travelled with the equation above. Be sure to use SI units as ROS is using that.

#!/usr/bin/env python3
import rospy
from nav_msgs.msg import Odometry
from std_msgs.msg import Int16
from math import cos, sin, pi

# Define variables for encoder ticks and wheelbase
left_ticks = 0
right_ticks = 0
wheelbase = 0.4  # Example value, adjust based on your robot

# Define variables for current pose and orientation
current_x = 0.0
current_y = 0.0
current_theta = 0.0

odom = Odometry()

def left_ticks_callback(msg):
    global left_ticks
    left_ticks = msg.data

def right_ticks_callback(msg):
    global right_ticks
    right_ticks = msg.data

def publish_odometry():
    global left_ticks, right_ticks, current_x, current_y, current_theta, odom

    l_revolutions = left_ticks / 280
    left_distance = 2 * pi * 0.065 * l_revolutions
    r_revolutions = right_ticks / 280
    right_distance = 2 * pi * 0.065 * r_revolutions

    # Calculate change in position and orientation
    delta_theta = (right_distance - left_distance) / wheelbase
    delta_x = (left_distance + right_distance) / 2.0 * cos(delta_theta)
    delta_y = (left_distance + right_distance) / 2.0 * sin(delta_theta)

    # Update current pose and orientation
    current_x += delta_x
    current_y += delta_y
    current_theta += delta_theta

    # Create Odometry message
    odom.header.stamp = rospy.Time.now()
    odom.pose.pose.position.x = current_x
    odom.pose.pose.position.y = current_y
    odom.pose.pose.orientation.z = sin(current_theta / 2.0)
    odom.pose.pose.orientation.w = cos(current_theta / 2.0)
    
def main():
    global odom

    rospy.init_node('encoder_to_odometry')

    # Subscribe to left and right ticks topics
    rospy.Subscriber('left_ticks', Int16, left_ticks_callback)
    rospy.Subscriber('right_ticks', Int16, right_ticks_callback)

    # Create Odometry publisher
    odom_pub = rospy.Publisher('odom', Odometry, queue_size=10)

    rate = rospy.Rate(10)  # Publish at 10 Hz

    while not rospy.is_shutdown():
        publish_odometry()
        odom_pub.publish(odom)
        rate.sleep()

if __name__ == '__main__':
    try:
        main()
    except rospy.ROSInterruptException:
        pass

Again I’m no specialist but I think the way you compute the values are pretty ok. But one very important thing is the way and how fast you get the ticks.

What I have done with my bot (which Im still building) is use a Arduino specifically for the motor control. And I use an interrupt to count the amount of pulses during a time interval. Than I compute the speed in CPS. which gives me eventually the speed.

If I were you I would first be very sure that the ticks are accurate measured you could check this with a scope if you have this at hand.
I would also change the variable names dont call your four wheels x,y,z,w but something like LeftFront, RightBack e.g. Just to don’t get confused with positions cause we use x, y for the position in the coordinate system.

further your code seems to be ok if I take a fast look, I would have to sit down to analyze it thoroughly.

Ohw and I almost forgot to mention 280 pulses for one revolution? Isn’t that a bit high? I dont know what kind of motors and encoders you use. Do you have some specifications a link or so?

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