1
$\begingroup$

Rosanswers logo

Hello, I'm using a Turtlebot with Kobuki base and running Ros Hydro on Ubuntu 12.04.

I need the Turtlebot to move in the shape of a square and guiding myself by this codes: albany , turtlebot motion and turtlebot tutorials, I put together a code that only sends the appropriate cmd_vel messages to make the robot move at a certain speed for a chosen time and another one that uses tf information from odom->base_footprint to make the robot move a chosen distance at a certain speed.

I was first testing the codes on turtlesim and they seemed to work well, but when I tested them on the gazebo turtlebot simulator and on the real turtlebot this was the outcome (obtained from the /odom topic on rviz):

Gazebo Simulation - From the code that doesn't use tf: Gazebo Simulation - From the code that doesn't use tf

Gazebo Simulation - From the code that uses the odom->base_footprint tf: Gazebo Simulation - From the code that uses the odom->base_footprint tf:

Real Turtlebot - From the code that doesn't use tf: Real Turtlebot - From the code that doesn't use tf

Real Turtlebot - From the code that uses the odom->base_footprint tf: Real Turtlebot - From the code that uses the odom->base_footprint tf

From what I've read the odom->base_footprint tf uses the wheel odometry and IMU data and the kobuki base already comes with a calibrated gyro, so I don't think the problem is in the odometry tf. Also, the movement of the turtlebot with the code that doesn't use the tf looks similar to the one the /odom topic shows.

The result from the real turtlebot is terrible, but I was surprised that even in the simulation the code doesn't work well. I don't really know how to improve this results, because I expected that the way to improve the first code was to use the one that implements the tf and that one is the one that works the worst.

Am I misusing the tfs or am I missing something particular about the turtlebot with the messages I'm sending? at least in the first code it looks as if the robot doesn't move as much as the speed would indicate but the tf should be indifferent to that. I read the similar questions in the FAQs but none of them help me solve this.

Thank you very much in advance and sorry for the rviz plots, I didn't find another way to get the trajectory of the robot.


The two codes are below:


Code that only sends the appropriate cmd_vel messages to make the robot move at a certain speed for a chosen time:

#!/usr/bin/env python
# http://library.isr.ist.utl.pt/docs/roswiki/rospy%282f%29Overview%282f%29Time.html
""" Example code of how to move a robot around the shape of a square. """

import roslib
import rospy
import math
import time
from geometry_msgs.msg import Twist


class square:  """ This example is in the form of a class. """

def __init__(self):
    """ This is the constructor of our class. """
    # register this function to be called on shutdown
    rospy.on_shutdown(self.cleanup)

    # publish to cmd_vel
    self.p = rospy.Publisher('cmd_vel', Twist)
#twist = Twist()

    # give our node/publisher a bit of time to connect
    rospy.sleep(1)

    # slow rate, 2 seconds sleep
    r = rospy.Rate(0.5)


    for i in range(4):

        # create a Twist message, fill it in to drive forward
        twist = Twist()
    start = rospy.get_time()
    print(rospy.get_time())
    while rospy.get_time()-start<4:
            twist.linear.x = 0.25; #move 0.25 m/s
    twist.linear.y = 0;
    twist.linear.z = 0;
    twist.angular.x = 0;
    twist.angular.y = 0;
    twist.angular.z = 0;
            self.p.publish(twist)
    rospy.loginfo("Moving the robot forward.")
        r.sleep()


        twist = Twist()
    start = rospy.get_time()
    print(rospy.get_time())
    while rospy.get_time()-start<2:
            twist.linear.x = 0;
    twist.linear.y = 0;
    twist.linear.z = 0;
    twist.angular.x = 0;
    twist.angular.y = 0;
        twist.angular.z = math.pi/4.0; #move pi/4 rad/sec
            self.p.publish(twist)
    rospy.loginfo("Turning the robot")
        r.sleep()

def cleanup(self):
    # stop the robot!
    twist = Twist()
    self.p.publish(twist)

if __name__=="__main__":
    rospy.init_node('control', anonymous=True)
    square()

This code uses tf information from odom->base_footprint to make the robot move a chosen distance at a certain speed:

#!/usr/bin/env python

""" Example code of how to move a robot around the shape of a square, using tf. """
# we always import these
import roslib
import rospy
import tf
import math

# recall: robots generally take base movement commands on a topic 
#  called "cmd_vel" using a message type "geometry_msgs/Twist"
from geometry_msgs.msg import Twist



class square:
    """ This example is in the form of a class. """
def __init__(self):
    """ This is the constructor of our class. """
print 'inwut'
    # register this function to be called on shutdown
    rospy.on_shutdown(self.cleanup)

    self.listener = tf.TransformListener()
print 'k1'

    # publish to cmd_vel
    self.p = rospy.Publisher('cmd_vel', Twist)
    # give our node/publisher a bit of time to connect
    rospy.sleep(1.0)

    twist = Twist()

#first = True
for i in range(2):
    print 'hey'
    done = False
    first = 1
    print first

    while not done:
        # create a Twist message, fill it in to drive forward
        twist.linear.x = 0.2;
        twist.angular.z = 0;
        self.p.publish(twist)
        rospy.loginfo("moving forward")
        
        try:

        ((new_x,y,z), rot) = self.listener.lookupTransform('odom', 'base_footprint', rospy.Time(0))

        except (tf.LookupException, tf.ConnectivityException):
            rospy.logerr("AHHHH")

        #print 'mid!'


        if first:
        orig_x=new_x
        first=0
        print 'first'       

        done=bool(abs(new_x-orig_x)>0.8)

        print done
        print new_x-orig_x

    done = False
    first = 1

    while not done:

        twist.angular.z = math.pi/4.0; #turns at pi/4 degrees/sec
        twist.linear.x=0;
        self.p.publish(twist)
        rospy.loginfo("turning")

        try:
                ((x,y,z), rot) = self.listener.lookupTransform('odom', 'base_footprint', rospy.Time(0))


        except (tf.LookupException, tf.ConnectivityException):
                rospy.logerr("AHHHH")

        (phi, psi, theta) = tf.transformations.euler_from_quaternion(rot)

        if first:
            orig_ang=theta
            first=0
        done = bool(abs(theta-orig_ang)>=math.pi/2.0)   

    done = False
    first = 1
    print first

    while not done:
        # create a Twist message, fill it in to drive forward
        twist.linear.x = 0.2;
        twist.angular.z = 0;
        self.p.publish(twist)
        rospy.loginfo("moving forward")
        
        try:

        ((x,new_y,z), rot) = self.listener.lookupTransform('odom', 'base_footprint', rospy.Time(0))

        except (tf.LookupException, tf.ConnectivityException):
            rospy.logerr("AHHHH")

        #print 'mid!'


        if first:
        orig_y=new_y
        first=0
        print 'first'       

        done=bool(abs(new_y-orig_y)>0.8)

        print done
        print new_x-orig_x

    done = False
    first = 1

    while not done:

        twist.angular.z = math.pi/16.0;
        twist.linear.x=0;
        self.p.publish(twist)
        rospy.loginfo("turning")

        try:
                ((x,y,z), rot) = self.listener.lookupTransform('odom', 'base_footprint', rospy.Time(0))


        except (tf.LookupException, tf.ConnectivityException):
                rospy.logerr("AHHHH")

        (phi, psi, theta) = tf.transformations.euler_from_quaternion(rot)

        if first:
            orig_ang=theta
            first=0
        done = bool(abs(theta-orig_ang)>=math.pi/2.0)      
        

    
def cleanup(self):
    # stop the robot!
    twist = Twist()
    self.p.publish(twist)

if __name__=="__main__":
    rospy.init_node('square')
    try:
        square()
    except:
        pass

Originally posted by Athria on ROS Answers with karma: 78 on 2015-05-27

Post score: 0

$\endgroup$

2 Answers 2

1
$\begingroup$

Rosanswers logo

What are you plotting as the ground truth, I'm pretty sure that's the odometry and I think it's much better than your control algorithm. Your code is basically doing open loop control to hit a target angle and then assuming that the robot will stop immediately. Then driving forward at a known speed or distance and expecting it to stop immediately.

Your timing based turns consistently understeer due to not accounting for acceleration, and your tf based turns consistently oversteer due to not accounting for decceleration. Likewise the distances time based are similar or shorter than expected, while the drive until final distance go to far due not counting for accelerations and latency.

To get good following performance you should be continuously homing to your goal with a controller, and correcting for errors which build up as you drive.


Originally posted by tfoote with karma: 58457 on 2015-05-27

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by Athria on 2015-05-28:
I am plotting the output of the /odom topic (that is published when I run the turtlebot_gazebo for the simulation and minimal.launch for the real robot), I thought that topic was giving me the combined odometry of IMU and wheels.

Comment by Athria on 2015-05-28:
And thank you for pointing out the control flaw, I will rethink how I'm using the tf measurements to account for deceleration.

$\endgroup$
0
$\begingroup$

Rosanswers logo

This sounds like a homework assignment (which I say because I had the exact same assignment in my first robotics class), and you are discovering exactly what the assignment is trying to teach you. I'm not going to give you the answer, but I'll present a few things to think about:

  • Is it possible to create a robot that will drive at exactly the velocity you tell it to?
  • What happens if there's even a 0.0001% difference between the velocity you expect, and the velocity at which the robot is actually moving? How does that change over time?
  • How good is the clock on your computer? What is happening in the condition rospy.get_time()-start<4? In one iteration rospy.get_time()-start<4 is true, and the next it is false, and a nonzero amount of time passed. What did your robot do in that time?

Originally posted by Dan Lazewatsky with karma: 9115 on 2015-05-27

This answer was NOT ACCEPTED on the original site

Post score: 1


Original comments

Comment by Athria on 2015-05-27:
Hello, thank you very much for the answer. My main goal is to test how the libfovis and viso2 visual odometry packages respond to different lightning conditions and environments, but for that I wanted a repeatable test so I thought the turtlebot was the best choice

Comment by Athria on 2015-05-27:
Since I can compare the trajectory without odometry, with imu+wheel odometry and with the VOs. I thought the clock and loop errors wouldn't affect that much, since they didn't affect the turtlesim but maybe it got worse on gazebo because it is much heavier,

Comment by Dan Lazewatsky on 2015-05-27:
You may be able to adjust things in gazebo to make this work better, but you're still going to run into discretization errors which will prevent things from working perfectly. If you want to run things on a real robot, you'll need something which provides better odometry.

Comment by Athria on 2015-05-27:
and I tought the the cumulative error from the velocity would affect the real turtlebot but not the simulation. I did expect an improvement when using the tf because I don't depend on time or on the acurracy of the speed anymore and the odometry seems to work better than what the tf code shows

Comment by Athria on 2015-05-27:
Sorry, I didn't read the last comment before. I thought the turtlebot's own odometry might be good enough since there are examples of people using the odom tf sucessfully to move in predefined trajectories, so maybe there's something wrong with my hardware instead of my code?

Comment by Dan Lazewatsky on 2015-05-27:
Odometry itself is generally not very good. Can you check if robot_pose_ekf is running? That will integrate odometry and IMU to give you a better estimate, but I still wouldn't trust it too much.

Comment by Athria on 2015-05-28:
robot_pose_ekf is being called on the turtlebot_bringup/package.xml as run_depend, but the odom_combined->base_footprint frame is not being published, the only one that appears is odom->base_footprint. I assumed that the odom-base_footprint was coming from the ekf since I don't have other odometry

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.