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 too exact for a robot if both angles should be exactly 0
speed.linear.x = 0.0
speed.angular.z = 0.3
else:
speed.linear.x = 0.3 #drive towards goal
speed.angular.z = 0.0
pub.publish(speed)
r.sleep()
Edit: Hey Delb,
thank you a lot for your answer!
It is not directly intended to just turn left but i thought that it would be easier to get started with only one direction and to add a logic about in which direction to turn later.
I will definitely try to implement your suggestion and see if it works.
SOLUTION: This is the code I ended up with, which seems to work pretty well.
#! /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, sin, cos, pow, sqrt
#start is x:0, y:0
x = 0.0
y = 0.0
theta = 0.0 #current angle of robot
move_forward = False
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 = 2
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
dist = sqrt(pow(inc_x, 2) + pow(inc_y, 2)) #calculate distance
#find out which turndirection is better
# the bigger the angle, the bigger turn, - when clockwise
turn = atan2(sin(angle_to_goal-theta), cos(angle_to_goal-theta))
if abs(angle_to_goal - theta) < 0.1: #0.1 because it too exact for a robot if both angles should be exactly 0
move_forward = True
speed.angular.z = 0.2 * turn
if move_forward == True:
#keep speed between 0.3 and 0.7
if 0.1 * dist > 0.3 and 0.1 * dist < 0.7:
speed.linear.x = 0.05 * dist
elif 0.1 * dist > 0.7:
speed.linear.x = 0.7
else:
speed.linear.x = 0.3
pub.publish(speed)
r.sleep()
Originally posted by SpaceTime on ROS Answers with karma: 50 on 2019-01-21
Post score: 0