XTDrone/robocup/control_actor.py

390 lines
20 KiB
Python
Executable File

import rospy
import random
from ros_actor_cmd_pose_plugin_msgs.msg import ActorMotion
from geometry_msgs.msg import Point
from gazebo_msgs.srv import GetModelState
from std_msgs.msg import String
import sys
import numpy
import copy
from nav_msgs.msg import Odometry
from ObstacleAvoid import ObstacleAviod
import math
class ControlActor:
def __init__(self, actor_id):
self.count = 0
self.shooting_count = 0
self.uav_num = 6
self.actor_num = 6
self.vehicle_type = 'typhoon_h480'
self.f = 10
self.flag = True
self.distance_flag = True
self.suitable_point = True
self.get_moving = False
self.x = 0.0
self.y = 0.0
# self.x_max = 50.0
# self.x_min = -10.0
# self.y_max = -20.0
# self.y_min = -30.0
self.x_max = 150.0
self.x_min = -50.0
self.y_max = 50.0
self.y_min = -50.0
self.id = actor_id
self.velocity = 1.5
self.avoid = ActorMotion()
self.last_pose = Point()
self.current_pose = Point()
self.target_motion = Point()
self.avoid.v = 2
# obstacle avoidance:
self.Obstacleavoid = ObstacleAviod() #ji wu
self.left_actors = range(self.actor_num)
self.avoid_finish_flag = True
self.subtarget_count = 0
self.subtarget_length = 0
self.subtarget_pos = []
self.arrive_count = 0
self.escape_suce_flag = False
self.gazebo_actor_pose = Point()
self.gazebo_uav_pose = [Point() for i in range(self.uav_num)]
self.gazebo_uav_twist = [Point()for i in range(self.uav_num)]
self.dis_actor_uav = [0.0 for i in range(self.uav_num)] # distance between uav and actor
self.tracking_flag = [0 for i in range(self.uav_num)] # check if there is a uav tracking 'me'
self.catching_flag = 0 # if there is a uav tracking 'me' for a long time
self.catching_uav_num = 10 # get the number of uav of which is catching 'me'
#self.black_box = numpy.array([[[-34, -19], [16, 34]], [[5, 20], [10, 28]], [[53, 68], [13, 31]], [[70, 84], [8, 20]], [[86, 102], [10, 18]], [[77, 96], [22, 35]], [[52, 71], [-34, -25]], [[-6, 6], [-35, -20]], [[12, 40], [-20, -8]], [[-7, 8], [-21, -9]], [[-29, -22], [-16, -27]], [[-37, -30], [-27, -12]], [[-38, -24], [-36, -29]]])
self.black_box = [[[52.2, 55.2],[-10.0, -5.72]], \
[[78, 91], [-34.6, -27]],[[2, 10], [33, 37]], [[-36.0, -19.0], [16.0, 34.5]], [[3.0, 23.0], [10.0, 26.0]], [[54, 70.0], [14, 31.3]], \
[[70.7, 84.5], [8.5, 19.5]], [[87.3, 101.7], [10.9, 17.2]], [[78, 95.7], [21.2, 35.5]], [[52, 71], [-36, -26]], [[-6.4, 6.5], [-20.4, -9.6]], \
[[13.5, 40.5], [-23.5, -4.5]], [[-6.0, 6.0], [-35.0, -21.0]], [[-28.8, -22.5], [-28.5, -14]], [[-37, -23], [-36, -30]], \
[[-36.5, -30.3], [-26.5, -12]], [[2.0,9.2],[33.3,36.7]]]
self.box_num = len(self.black_box)
self.cmd_pub = rospy.Publisher('/actor_' + self.id + '/cmd_motion', ActorMotion, queue_size=10)
#self.black_box = numpy.array(
# [[[-32, -21], [18, 32]], [[7, 18], [12, 26]], [[55, 66], [15, 29]], [[72, 82], [10, 18]],
# [[88, 100], [12, 16]], [[79, 94], [24, 33]], [[54, 69], [-34, -27]], [[-4, 4], [-33, -22]],
# [[14, 38], [-18, -10]], [[-7, 6], [-19, -11]], [[-27, -24], [-14, -29]], [[-35, -32], [-25, -14]],
# [[-36, -24], [-34, -31]]])
self.gazeboModelstate = rospy.ServiceProxy('gazebo/get_model_state', GetModelState)
print('actor_' + self.id + ": " + "communication initialized")
self.state_uav0_sub = rospy.Subscriber("/xtdrone/"+self.vehicle_type+"_0/ground_truth/odom", Odometry, self.cmd_uav0_pose_callback)
self.state_uav1_sub = rospy.Subscriber("/xtdrone/"+self.vehicle_type+"_1/ground_truth/odom", Odometry, self.cmd_uav1_pose_callback)
self.state_uav2_sub = rospy.Subscriber("/xtdrone/"+self.vehicle_type+"_2/ground_truth/odom", Odometry, self.cmd_uav2_pose_callback)
self.state_uav3_sub = rospy.Subscriber("/xtdrone/"+self.vehicle_type+"_3/ground_truth/odom", Odometry, self.cmd_uav3_pose_callback)
self.state_uav4_sub = rospy.Subscriber("/xtdrone/"+self.vehicle_type+"_4/ground_truth/odom", Odometry, self.cmd_uav4_pose_callback)
self.state_uav5_sub = rospy.Subscriber("/xtdrone/"+self.vehicle_type+"_5/ground_truth/odom", Odometry, self.cmd_uav5_pose_callback)
self.left_actors_sub = rospy.Subscriber("/left_actors",String,self.left_actors_callback)
def left_actors_callback(self, msg):
left = msg.data
left = left.replace('[',',')
left = left.replace(']',',')
left = left.split(',')
left_actors = []
for i in left[1:-1]:
if i == '':
continue
left_actors.append(int(i))
self.left_actors = left_actors
def cmd_uav0_pose_callback(self, msg):
self.gazebo_uav_pose[0] = msg.pose.pose.position
self.gazebo_uav_twist[0] = msg.twist.twist.linear
def cmd_uav1_pose_callback(self, msg):
self.gazebo_uav_pose[1] = msg.pose.pose.position
self.gazebo_uav_twist[1] = msg.twist.twist.linear
def cmd_uav2_pose_callback(self, msg):
self.gazebo_uav_pose[2] = msg.pose.pose.position
self.gazebo_uav_twist[2] = msg.twist.twist.linear
def cmd_uav3_pose_callback(self, msg):
self.gazebo_uav_pose[3] = msg.pose.pose.position
self.gazebo_uav_twist[3] = msg.twist.twist.linear
def cmd_uav4_pose_callback(self, msg):
self.gazebo_uav_pose[4] = msg.pose.pose.position
self.gazebo_uav_twist[4] = msg.twist.twist.linear
def cmd_uav5_pose_callback(self, msg):
self.gazebo_uav_pose[5] = msg.pose.pose.position
self.gazebo_uav_twist[5] = msg.twist.twist.linear
def loop(self):
rospy.init_node('actor_' + self.id)
rate = rospy.Rate(self.f)
while not rospy.is_shutdown():
self.avoid.v = 2.0
self.count = self.count + 1
# get the pose of uav and actor
if not int(self.id) in self.left_actors:
print('actor_' + self.id + ' has been deleted')
break
try:
get_actor_state = self.gazeboModelstate('actor_' + self.id, 'ground_plane')
self.last_pose = self.current_pose
self.gazebo_actor_pose = get_actor_state.pose.position
self.current_pose = self.gazebo_actor_pose
except rospy.ServiceException as e:
print("Gazebo model state service"+self.id+" call failed: %s") % e
self.current_pose.x = 0.0
self.current_pose.y = 0.0
self.current_pose.z = 1.25
# collosion: if the actor is in the black box, then go backward and update a new target position
# update new random target position
if (self.avoid_finish_flag and self.distance_flag):
while self.suitable_point:
while_time = 0
self.suitable_point = False
self.x = random.uniform(self.x_min, self.x_max)
self.y = random.uniform(self.y_min, self.y_max)
for i in range(self.box_num):
if (self.x > self.black_box[i][0][0]-1.5) and (self.x < self.black_box[i][0][1]+1.5):
if (self.y > self.black_box[i][1][0]-1.5) and (self.y < self.black_box[i][1][1]+1.5):
self.suitable_point = True
while_time = while_time+1
#print self.id + 'while time : ', while_time
break
self.target_motion.x = self.x
self.target_motion.y = self.y
self.flag = False
self.distance_flag = False
self.suitable_point = True
self.escape_suce_flag = False
if self.target_motion.x < self.x_min:
self.target_motion.x = self.x_min
elif self.target_motion.x > self.x_max:
self.target_motion.x = self.x_max
if self.target_motion.y < self.y_min:
self.target_motion.y = self.y_min
elif self.target_motion.y > self.y_max:
self.target_motion.y = self.y_max
try:
self.subtarget_pos = self.Obstacleavoid.GetPointList(self.current_pose, self.target_motion, 1) # current pose, target pose, safe distance
self.subtarget_length = len(self.subtarget_pos)
middd_pos = [Point() for k in range(self.subtarget_length)]
middd_pos = copy.deepcopy(self.subtarget_pos)
self.avoid.x = copy.deepcopy(middd_pos[0].x)
self.avoid.y = copy.deepcopy(middd_pos[0].y)
#self.avoid_start_flag = True
if self.id == '5' or self.id == '4':
print self.id+' general change position'
print 'current_position: ' + self.id+' ', self.current_pose
print 'middd_pos: '+ self.id+' ', middd_pos
print '\n'
except:
dis_list = [0,0,0,0]
for i in range(len(self.black_box)):
if (self.current_pose.x > self.black_box[i][0][0]-1.0) and (self.current_pose.x < self.black_box[i][0][1]+1.0):
if (self.current_pose.y > self.black_box[i][1][0]-1.0) and (self.current_pose.y < self.black_box[i][1][1]+1.0):
dis_list[0] = abs(self.current_pose.x - (self.black_box[i][0][0] - 1.0))
dis_list[1] = abs(self.current_pose.x - (self.black_box[i][0][1] + 1.0))
dis_list[2] = abs(self.current_pose.y - (self.black_box[i][1][0] - 1.0))
dis_list[3] = abs(self.current_pose.y - (self.black_box[i][1][1] + 1.0))
dis_min = dis_list.index(min(dis_list))
self.subtarget_length = 1
if dis_min == 0:
self.avoid.x = self.black_box[i][0][0] - 1.0
self.avoid.y = self.current_pose.y
elif dis_min == 1:
self.avoid.x = self.black_box[i][0][1] + 1.0
self.avoid.y = self.current_pose.y
elif dis_min == 2:
self.avoid.y = self.black_box[i][1][0] - 1.0
self.avoid.x = self.current_pose.x
else:
self.avoid.y = self.black_box[i][1][1] + 1.0
self.avoid.x = self.current_pose.x
break
if self.id == '5' or self.id == '4':
print self.id+'change position except'
print 'current_position: ' + self.id+' ', self.current_pose
print 'target_motion: '+ self.id+' ', self.target_motion
print '\n'
self.avoid_finish_flag = False
distance = (self.current_pose.x - self.avoid.x) ** 2 + (
self.current_pose.y - self.avoid.y) ** 2
if distance < 0.01:
self.arrive_count += 1
if self.arrive_count > 5:
self.distance_flag = True
self.arrive_count = 0
if self.catching_flag == 2:
self.catching_flag = 0
else:
self.distance_flag = False
else:
self.arrive_count = 0
self.distance_flag = False
# dodging uavs: if there is a uav catching 'me', escape
for i in range(self.uav_num):
if ((self.gazebo_uav_twist[i].x)**2+(self.gazebo_uav_twist[i].y)**2) > 1.0:
self.dis_actor_uav[i] = ((self.current_pose.x-self.gazebo_uav_pose[i].x)**2+(self.current_pose.y-self.gazebo_uav_pose[i].y)**2)**0.5
if self.dis_actor_uav[i] < 20.0 and (self.catching_flag == 0):
self.tracking_flag[i] = self.tracking_flag[i]+1
if self.tracking_flag[i] > 20: # 2s and excape
self.catching_flag = 1
self.tracking_flag[i] = 0
self.catching_uav_num = i
print('catch', self.id)
print('catch', self.id)
break
if self.dis_actor_uav[i] >= 20.0:
# if self.catching_flag[i] == 1 or self.catching_flag[i] == 2:
# self.escape_suce_flag = True
self.tracking_flag[i] = 0
self.catching_flag = 0
self.catching_uav_num = 10
# # escaping (get a new target position)
if self.catching_flag == 1:
flag_k = 0
angle = self.pos2ang(self.gazebo_uav_twist[self.catching_uav_num].x,self.gazebo_uav_twist[self.catching_uav_num].y)
print 'angle: ', angle
tar_angle = angle - math.pi/2 # escape to the target vertical of the uav
if tar_angle == math.pi/2:
flag_k = 1
elif (tar_angle == -math.pi/2) or (tar_angle == 3 * math.pi/2):
flag_k = 2
else:
k = math.tan(tar_angle)
print 'k: ', k
if (tar_angle < 0) and (flag_k == 0):
y = k*(self.x_max-self.gazebo_uav_pose[self.catching_uav_num].x)+self.gazebo_uav_pose[self.catching_uav_num].y
if y < self.y_min:
self.target_motion.y = self.y_min
self.target_motion.x = (self.y_min - self.gazebo_uav_pose[self.catching_uav_num].y) / k + self.gazebo_uav_pose[self.catching_uav_num].x
else:
self.target_motion.y = y
self.target_motion.x = self.x_max
elif (tar_angle > 0) and (tar_angle < math.pi/2) and (flag_k == 0):
y = k*(self.x_max-self.gazebo_uav_pose[self.catching_uav_num].x)+self.gazebo_uav_pose[self.catching_uav_num].y
if y > self.y_max:
self.target_motion.y = self.y_max
self.target_motion.x = (self.y_max - self.gazebo_uav_pose[self.catching_uav_num].y) / k + self.gazebo_uav_pose[self.catching_uav_num].x
else:
self.target_motion.y = y
self.target_motion.x = self.x_max
elif (tar_angle < math.pi) and (tar_angle > math.pi/2) and (flag_k == 0):
y = k*(self.x_min-self.gazebo_uav_pose[self.catching_uav_num].x)+self.gazebo_uav_pose[self.catching_uav_num].y
if y > self.y_max:
self.target_motion.y = self.y_max
self.target_motion.x = (self.y_max - self.gazebo_uav_pose[self.catching_uav_num].y) / k + self.gazebo_uav_pose[self.catching_uav_num].x
else:
self.target_motion.y = y
self.target_motion.x = self.x_min
elif (tar_angle > math.pi) and (tar_angle < 3*math.pi/2) and (flag_k == 0):
y = k*(self.x_min-self.gazebo_uav_pose[self.catching_uav_num].x)+self.gazebo_uav_pose[self.catching_uav_num].y
if y < self.y_min:
self.target_motion.y = self.y_min
self.target_motion.x = (self.y_min - self.gazebo_uav_pose[self.catching_uav_num].y) / k + self.gazebo_uav_pose[self.catching_uav_num].x
else:
self.target_motion.y = y
self.target_motion.x = self.x_min
elif flag_k == 1:
self.target_motion.x = self.gazebo_uav_pose[self.catching_uav_num].x
self.target_motion.y = self.y_max
elif flag_k == 2:
self.target_motion.x = self.gazebo_uav_pose[self.catching_uav_num].x
self.target_motion.y = self.y_min
if self.id == 5:
print self.id + ' self.curr_pose:', self.gazebo_uav_pose[self.catching_uav_num]
print self.id + ' self.target_motion:', self.target_motion
print 'escaping change position'
try:
print self.id+'general change position'
self.subtarget_pos = self.Obstacleavoid.GetPointList(self.current_pose, self.target_motion, 1) # current pose, target pose, safe distance
self.subtarget_length = 1
# middd_pos = [Point() for k in range(self.subtarget_length)]
# middd_pos = copy.deepcopy(self.subtarget_pos)
self.avoid.x = self.subtarget_pos[0].x
self.avoid.y = self.subtarget_pos[0].y
self.catching_flag = 2
except:
self.avoid.x = self.target_motion.x
self.avoid.y = self.target_motion.y
self.catching_flag = 1
# check if the actor is shot:
if self.get_moving:
distance_change = (self.last_pose.x - self.current_pose.x)**2 + (self.last_pose.y - self.current_pose.y)**2
if distance_change < 0.00001:
self.shooting_count = self.shooting_count+1
if self.shooting_count > 1000:
print('shot', self.id)
print('shot', self.id)
self.distance_flag = False
self.suitable_point = True
self.avoid_finish_flag = True
self.shooting_count = 0
else:
self.shooting_count = 0
if not self.avoid_finish_flag:
if self.distance_flag:
self.subtarget_count += 1
self.distance_flag = False
#print self.id+ ': I am avoiding'
#self.distance_flag = False
#self.subtarget_length = len(middd_pos)
if self.subtarget_count >= self.subtarget_length:
self.avoid_finish_flag = True
self.subtarget_count = 0
else:
self.avoid.x = middd_pos[self.subtarget_count].x
self.avoid.y = middd_pos[self.subtarget_count].y
'''
if self.catching_flag == 1 or self.catching_flag == 2:
self.target_motion.v = 3
else:
self.target_motion.v = 2
if self.count % 200 == 0:
print self.id + ' vel:', self.target_motion.v
'''
#reduce difficulty
self.avoid.v = 1
if self.id == 5:
print 'self.avoid:', self.avoid
self.cmd_pub.publish(self.avoid)
rate.sleep()
def pos2ang(self, deltax, deltay): #([xb,yb] to [xa, ya])
if not deltax == 0:
angle = math.atan2(deltay,deltax)
if (deltay > 0) and (angle < 0):
angle = angle + math.pi
elif (deltay < 0) and (angle > 0):
angle = angle - math.pi
elif deltay == 0:
if deltax > 0:
angle = 0.0
else:
angle = math.pi
else:
if deltay > 0:
angle = math.pi / 2
elif deltay <0:
angle = -math.pi / 2
else:
angle = 0.0
if angle < 0:
angle = angle + 2 * math.pi # 0 to 2pi
return angle
if __name__=="__main__":
controlactors = ControlActor(sys.argv[1])
controlactors.loop()