Untitled
unknown
plain_text
3 years ago
12 kB
5
Indexable
#!/usr/bin/env python
from planner import point_to_line
import rospy
from std_msgs.msg import Float32MultiArray
import math
import time
from geometry_msgs.msg import Twist
import numpy as np
from nav_msgs.msg import Odometry
def calc_distance(p_1, p_2):
return math.sqrt((p_2[0]-p_1[0])**2 + (p_2[1]-p_1[1])**2)
def calculate_angle(p_1, p_2, p_3):
'''
p_1 is the point it is coming from
p_2 is the point it is currently at
p_3 is the point it is going to
'''
angle_1 = math.atan((p_2[1]-p_1[1])/(p_2[0]-p_1[0]))
angle_2 = math.atan((p_3[1]-p_2[1])/(p_3[0]-p_2[0]))
# return (angle_1 - angle_2)*180/math.pi
return angle_2 - angle_1
def quat_2_euler(ox, oy, oz, ow):
t3 = +2.0 * (ow * oz + ox * oy)
t4 = +1.0 - 2.0 * (oy * oy + oz * oz)
yaw_z = math.atan2(t3, t4)
return yaw_z
def get_sign(current, goal, dir):
vect1 = np.array([goal[0] - current[0], goal[1] - current[1]])/ np.linalg.norm([goal[0] - current[0], goal[1] - current[1]])
vect2 = np.array(dir)/np.linalg.norm(dir)
if round(np.dot(vect1, vect2), 2) < 0:
return -1
else:
return 1
class controller():
def __init__(self, path) -> None:
self.path = path
self.max_speed = 1
self.translating = False
self.rotating = False
self.num_of_points = len(path)
self.vec = 0
self.prev_orient = 0
self.current_pos = (0,0)
self.current_orient = 0
self.trans_speed = 0.1
self.rot_speed = 1
self.sub_odom = rospy.Subscriber('/odom', Odometry, self.get_pos)
self.kp_lin = 0.05
self.ki_lin = 0
self.kd_lin = 0.0
self.kp_ang = 0.01
self.ki_ang = 0
self.kd_ang = 0
self.error = 0
self.error_last = 0
self.integral_error = 0
self.derivative_error = 0
self.output = 0
def get_pos(self, data):
self.current_pos = (data.pose.pose.position.x, data.pose.pose.position.y)
ox, oy, oz, ow = data.pose.pose.orientation.x, data.pose.pose.orientation.y, data.pose.pose.orientation.z, data.pose.pose.orientation.w
self.current_orient = quat_2_euler(ox, oy, oz, ow)*180/math.pi
# def translate(self, p_a, p_b):
# self.translating = True
# time_required_to_translate = calc_distance(p_a, p_b)/self.trans_speed
# self.error = calc_distance(self.current_pos, p_b)
# pub = rospy.Publisher('cmd_vel', Twist, queue_size=10)
# move_cmd = Twist()
# move_cmd.linear.x = self.trans_speed
# now = rospy.Time.now()
# rate = rospy.Rate(100)
# #Move bot for required amount of time
# while rospy.Time.now() < now + rospy.Duration.from_sec(time_required_to_translate):
# pub.publish(move_cmd)
# rate.sleep()
# print('translated distance: ', calc_distance(p_a, p_b))
# print('current pos: ', self.current_pos, ' expected pos: ', p_b)
# def stop(self):
# pub = rospy.Publisher('cmd_vel', Twist, queue_size=10)
# move_cmd = Twist()
# move_cmd.linear.x = 0
# def rotate(self, angle):
# self.rotating = True
# time_required_to_rotate = (angle)/self.rot_speed
# prev = self.current_orient
# pub = rospy.Publisher('cmd_vel', Twist, queue_size=10)
# move_cmd = Twist()
# move_cmd.angular.z = self.rot_speed*get_sign(angle)
# now = rospy.Time.now()
# rate = rospy.Rate(100)
# print('time: ', time_required_to_rotate)
# #Rotate bot for required amount of time
# while rospy.Time.now() < now + rospy.Duration.from_sec(time_required_to_rotate):
# print(move_cmd)
# pub.publish(move_cmd)
# rate.sleep()
# print('expected rotation: ', angle*180/math.pi, ' actual rotation: ', self.current_orient - prev)
def mover(self):
print('number of nodes: ', len(self.path))
#To move from (0,0) to first point
# first_angle = math.atan(self.path[1][1]/self.path[1][0])
# print(first_angle)
# self.rotate(first_angle)
# self.translate((0,0), self.path[1])
#Traversing rest of the path
reached = False
point_idx = 0
self.rotate = True
self.translate = False
self.correction_protocol = False
pub = rospy.Publisher('cmd_vel', Twist, queue_size=10)
move_cmd = Twist()
rate = rospy.Rate(100)
while not reached:
#When final goal is reached
if calc_distance(self.current_pos, (6,6)) <= 0.1:
reached = True
break
goal = self.path[point_idx + 1]
#for rotation
if abs((math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.current_orient)> 0.5 and self.rotate:
rot_flag = 0
expected_rotation = (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.prev_orient
if expected_rotation < 0:
if goal[0] < self.current_pos[0]:
expected_rotation = 180 + expected_rotation
rot_flag = 1
# possible = (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.current_orient
if rot_flag == 1:
self.error = 180 + (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.current_orient
else:
self.error = (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.current_orient
self.integral_error += self.error
self.derivative_error = self.error - self.error_last
output = self.kp_ang*self.error + self.ki_ang*self.integral_error + self.kd_ang*self.derivative_error
# print('rotating')
move_cmd.angular.z = output
pub.publish(move_cmd)
rate.sleep()
if abs(self.error) <= 0.75:
self.rotate = False
self.translate = True
move_cmd.angular.z = 0
move_cmd.linear.x = 0
pub.publish(move_cmd)
if point_idx == 0:
print('expected rotation: ', math.atan(goal[1]/goal[0])*180/math.pi, ' actual rotation: ', self.current_orient)
print('error: ', self.error)
print('stopped rotating, starting transalation')
print('**************************************')
else:
print('expected rotation: ', expected_rotation
, ' actual rotation: ', self.current_orient - self.prev_orient)
print('error:', self.error)
print('stopped rotating, starting transalation')
print('**************************************')
#for translating
elif self.translate:
self.rotate = False
self.translate = True
self.error = calc_distance(self.current_pos, goal)
self.integral_error += self.error
self.derivative_error = self.error - self.error_last
self.error_last = self.error
output = self.kp_lin*self.error + self.ki_lin*self.integral_error + self.kd_lin*self.derivative_error
sign = get_sign(self.current_pos, goal, [goal[0] - self.path[point_idx][0], goal[1] - self.path[point_idx][1]])
move_cmd.linear.x = output*sign
# print('translating')
pub.publish(move_cmd)
rate.sleep()
if abs(math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0]))*180/math.pi - self.current_orient) > 1:
print('Too much deviation, initiating correction protocol')
print('deviation: ', abs(math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0]))*180/math.pi - self.current_orient))
self.translate = False
self.rotate = False
self.correction_protocol = True
if self.error <= 0.075:
print('expected coord ', goal, ' actual coord: ', self.current_pos)
print('error: ', self.error)
print('reached index: ', point_idx + 1)
print('stopped translating, starting rotation')
print('******************************************')
self.rotate = True
self.translate = False
self.correction_protocol = False
point_idx += 1
move_cmd.angular.z = 0
move_cmd.linear.x = 0
self.prev_orient = self.current_orient
pub.publish(move_cmd)
elif self.correction_protocol:
#stop the bot
move_cmd.angular.z = 0
move_cmd.linear.x = 0
pub.publish(move_cmd)
rot_flag = 0
expected_rotation = (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.prev_orient
if expected_rotation < 0:
if goal[0] < self.current_pos[0]:
expected_rotation = 180 + expected_rotation
rot_flag = 1
if rot_flag == 1:
self.error = 180 + (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.current_orient
else:
self.error = (math.atan((goal[1] - self.current_pos[1])/(goal[0] - self.current_pos[0])))*180/math.pi - self.current_orient
self.integral_error += self.error
self.derivative_error = self.error - self.error_last
output = self.kp_ang*self.error + self.ki_ang*self.integral_error + self.kd_ang*self.derivative_error
print(output)
move_cmd.angular.z = output
pub.publish(move_cmd)
rate.sleep()
if abs(self.error) <= 0.75:
self.rotate = False
self.translate = True
move_cmd.angular.z = 0
move_cmd.linear.x = 0
pub.publish(move_cmd)
print('correction complete')
print('*************************')
self.translate = True
self.correction_protocol = False
self.rotate = False
def callback(data):
path_nodes = []
published_data = data.data
for i in range(len(published_data)):
if i%2 == 0:
path_nodes.append((round(published_data[i], 3), round(published_data[i+1], 3)))
else:
continue
print(path_nodes)
control = controller(path_nodes)
control.mover()
def listener():
rospy.init_node('controller', anonymous=True)
data = rospy.wait_for_message('path', Float32MultiArray, timeout=None)
callback(data)
rospy.spin()
if __name__ == '__main__':
listener()Editor is loading...