ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | Q&A answers.ros.org

# Navigation of robot to goal point/Turning until robot faces goal-direction

SOLVED See Solution at the end of post

Problem: Hey there,

I'm currently working on a project about navigating a robot to a goal point.

I already wrote some code to tackle this task. The code uses the gazebo/modelstates topic to get the position and orientation of the robot. The angle_to_goal is calculated by looking at the currentPosition and the goalPosition.

The robot should turn, until the difference between the yaw of the robot and the angle_to_goal is 0 +/- a threshold of 0.1. If this is the case, the robot should drive towards the goal.

This code is working pretty well in some cases where the robot gets into the acceptable range well and drives straight without any correction needed.

In other cases the robot will turn, then drive a very small distance, then correct its course again a little bit and repeat this which leads to a very slow and jittery path. I can imagine that the problem is that the robot gets into the acceptable range of the angle at the very border of it, then starts driving which makes the difference of the angles grow and leads the robot to turn the robot again but not enough so that it drives relatively fluently afterwards. Another case is that the robot seems to overshoot the desired angle_range or immediately leave it and doesn't stop turning.

In both cases the robot does not really find its way but keeps being stuck, misses the right angle and continues in this sub-optimal behavior. I already tried different angular-velocities and also other thresholds.

As I am a total beginner I don't know if my guess of the problem could be right. I don't know how i could do to solve the problem or at least improve the rate of the robot getting the right direction at the first time. Thank you in advance for any help!

Here is the code:

#! /usr/bin/env python
import rospy
from gazebo_msgs.msg import ModelStates
from tf.transformations import euler_from_quaternion
from geometry_msgs.msg import Twist
from geometry_msgs.msg import Point
from math import atan2

#start is x:0, y:0
x = 0.0
y = 0.0
theta = 0.0     #current angle of robot

#import ipdb; ipdb.set_trace()

def callback(msg):
global x
global y
global theta

x = msg.pose[1].position.x
y = msg.pose[1].position.y
rot_q = msg.pose[1].orientation
(roll, pitch, theta) = euler_from_quaternion([rot_q.x, rot_q.y, rot_q.z, rot_q.w])

rospy.init_node ('subscriber')
sub = rospy.Subscriber('/gazebo/model_states', ModelStates, callback)
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)

speed = Twist()

r = rospy.Rate(4)

goal = Point()
goal.x = -2
goal.y = -1

while not rospy.is_shutdown():
inc_x = goal.x - x                      #distance robot to goal in x
inc_y = goal.y - y                      #distance robot to goal in y
angle_to_goal = atan2 (inc_y, inc_x)    #calculate angle through distance from robot to goal in x and y
print abs(angle_to_goal - theta)
if abs(angle_to_goal - theta) > 0.1:    #0.1 because it ...
edit retag close merge delete

Sort by » oldest newest most voted

First note here : is it intended for your robot to be only turning left ? That could be problematic if the robot deviates too much at the left of the goal, it would be turning for almost 2*pi instead of a little bit to the right to correct its orientation.

Anyway, you should be able to achieve what you want with some little changes :

1. I would directly set the angular speed equal to the angle difference. That would allow the robot to always correct its orientation when reaching the goal. So your angular speed at any time could be :

speed.angular.z = angle_to_goal - theta


That being said you might want to have a function calculating the shortest angle (because your calculation might return 3*pi/2 instead of -pi/2) not to be always turning too much and also to deal with the case when your robot is aligned to the goal but the calculation returns 2*pi. If it's not what you want I would still recommend to get the sign of the angular difference to allow your robot to turn left or right when needed.

2. I would change the condition. Instead of choosing between moving forward and turning, you could have a flag turning to true the first time your robot gets aligned to the goal and then allow it to move forward :

move_forward = False        #define this outside of the while loop
...
if abs(angle_to_goal - theta) > 0.1:
move_forward = True

speed.angular.z = angle_to_goal - theta   #the angular speed is always the angualr difference
if move_forward is True:
speed.linear = 0.3                #the linear speed is only set once the flag is True

3. If the robot has almost reached a goal but you are not exactly aligned with it and you are still moving forward at a constant speed, you might miss the goal (eventhough I don't know which tolerance you have) but to avoid that it is possible to also set the linear speed as the angular speed, but instead of the angular difference it would be the distance. Like that your robot will slow down when getting closer to the goal, letting you the time to adjust your orientation before missing the goal.

EDIT :

So if I understand the values right, if the coordinates are on the robots right side, I get a value between 0.0 and -pi returned and if its on the left its between 0.0 and pi? How do I effectively get which angle is smaller?

If you get the correct angle then yes but you won't get it simply with angle_to_goal - theta because angle_to_goal and theta will return a value between [-pi; pi] : If you have x > 0 a little angle, if you get angle_to_goal = pi - x and theta = -pi + x then angle_to_goal - theta = 2pi + 2x instead of 2x. So you have to modify the result of this angular difference, here's an exemple of a function (in C++) doing that :

float shortestAngleDifference(float th1, float th2)
{
float ...
more