moveitServer2.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. # 导入基本ros和moveit库
  2. from logging.handlers import RotatingFileHandler
  3. import os
  4. import moveit_msgs.msg
  5. import rospy, sys
  6. import moveit_commander
  7. import moveit_msgs
  8. from visualization_msgs.msg import Marker, MarkerArray
  9. from moveit_commander import MoveGroupCommander, PlanningSceneInterface, RobotCommander
  10. from moveit_msgs.msg import PlanningScene, ObjectColor,CollisionObject, AttachedCollisionObject,RobotTrajectory
  11. from moveit_msgs.msg import RobotState
  12. from moveit_msgs.msg import Constraints, PositionConstraint, OrientationConstraint
  13. from shape_msgs.msg import SolidPrimitive
  14. from sensor_msgs.msg import JointState
  15. import tf.transformations
  16. from trajectory_msgs.msg import JointTrajectory,JointTrajectoryPoint
  17. from geometry_msgs.msg import PoseStamped, Pose,Point,Vector3
  18. from copy import deepcopy
  19. import numpy as np
  20. import tf
  21. from tf.transformations import euler_from_quaternion,quaternion_from_euler,quaternion_from_euler, quaternion_multiply
  22. import math
  23. import traceback
  24. from lstrobot_planning.msg import JointTrajectoryPoint_ex,JointTrajectory_ex
  25. import json
  26. import termios
  27. from decorator_time import decorator_time
  28. import check
  29. from redis_publisher import Publisher
  30. pi = np.pi
  31. class MoveIt_Control:
  32. # TODO初始化程序
  33. def __init__(self, is_use_gripper=False):
  34. self.home_pose = []
  35. self.hf_num = 0
  36. self.hf_fail = []
  37. # Init ros config
  38. moveit_commander.roscpp_initialize(sys.argv)
  39. self.robot = moveit_commander.RobotCommander() #暂未使用
  40. self.arm = moveit_commander.MoveGroupCommander('manipulator')
  41. self.arm.set_goal_joint_tolerance(0.0001)
  42. self.arm.set_goal_position_tolerance(0.0005)
  43. self.arm.set_goal_orientation_tolerance(0.1)
  44. self.end_effector_link = self.arm.get_end_effector_link()
  45. # 设置机械臂基座的参考系
  46. self.reference_frame = 'base_link'
  47. self.arm.set_pose_reference_frame(self.reference_frame)
  48. # # 设置最大规划时间和是否允许重新规划
  49. self.arm.set_planning_time(10.0)
  50. self.arm.allow_replanning(True)
  51. self.arm.set_max_acceleration_scaling_factor(1)
  52. self.arm.set_max_velocity_scaling_factor(1)
  53. self.arm.set_num_planning_attempts(10)
  54. # 机械臂初始姿态
  55. #self.move_j() #备注,是否可以用move_j代替go_home来节省时间(待测试)
  56. self.go_home()
  57. self.home_pose = self.get_now_pose()
  58. # TODO关节规划,输入6个关节角度(单位:弧度)
  59. def move_j(self, joint_configuration=None, a=1, v=1):
  60. # 设置机械臂的目标位置,使用六轴的位置数据进行描述(单位:弧度)
  61. if joint_configuration == None:
  62. joint_configuration = [0, 0, 0, 0, 0, 0]
  63. self.arm.set_max_acceleration_scaling_factor(a)
  64. self.arm.set_max_velocity_scaling_factor(v)
  65. self.arm.set_joint_value_target(joint_configuration)
  66. rospy.loginfo("move_j:" + str(joint_configuration))
  67. self.arm.go()
  68. #rospy.sleep(1)
  69. # TODO获取机械臂当前位姿
  70. def get_now_pose(self):
  71. current_pose = self.arm.get_current_pose(self.end_effector_link).pose
  72. pose = []
  73. pose.append(current_pose.position.x)
  74. pose.append(current_pose.position.y)
  75. pose.append(current_pose.position.z)
  76. pose.append(current_pose.orientation.x)
  77. pose.append(current_pose.orientation.y)
  78. pose.append(current_pose.orientation.z)
  79. pose.append(current_pose.orientation.w)
  80. # 打印位姿信息
  81. #rospy.lohome_poseinfo("Current Pose: {}".format(pose))
  82. return pose
  83. #TODO move_p 路径约束
  84. def create_path_constraints2(self, start_point, end_point, r):
  85. #计算起点指向终点的向量
  86. vector = np.array([end_point[0]- start_point[0], end_point[1]- start_point[1], end_point[2]- start_point[2]])
  87. height = np.linalg.norm(vector) + 0.05 #高度延长16cm
  88. radius = r
  89. # 位置约束
  90. position_constraint = PositionConstraint() #实例化位置约束
  91. position_constraint.header.frame_id = "base_link" #此约束所指的机器人链接
  92. position_constraint.link_name = self.end_effector_link
  93. position_constraint.target_point_offset = Vector3(0, 0, 0) #目标点的偏移量
  94. position_constraint.weight = 1.0 #权重,'1'为硬约束
  95. #构建 shape_msgs/SolidPrimitive 消息
  96. bounding_volume = SolidPrimitive()
  97. bounding_volume.type = SolidPrimitive.CYLINDER #圆柱约束
  98. bounding_volume.dimensions = [height, radius] #圆柱的尺寸,[高度,半径]
  99. position_constraint.constraint_region.primitives.append(bounding_volume)
  100. #构建 geometry_msgs/Pose 消息,用于指定圆柱体在空间中的位置和姿态
  101. pose = Pose()
  102. pose.position.x = start_point[0] + vector[0] / 2 #圆柱的几何中心
  103. pose.position.y = start_point[1] + vector[1] / 2
  104. pose.position.z = start_point[2] + vector[2] / 2
  105. # 计算圆柱体的姿态
  106. z_axis = np.array([0, 0, 1])
  107. axis = np.cross(z_axis, vector) #计算两个向量(向量数组)的叉乘 叉乘返回的数组既垂直于a,又垂直于b
  108. angle = np.arccos(np.dot(z_axis, vector) / np.linalg.norm(vector)) #反余弦求角度
  109. q = tf.transformations.quaternion_about_axis(angle, axis) #通过旋转轴和旋转角返回四元数
  110. pose.orientation.x = q[0]
  111. pose.orientation.y = q[1]
  112. pose.orientation.z = q[2]
  113. pose.orientation.w = q[3]
  114. position_constraint.constraint_region.primitive_poses.append(pose)
  115. constraints = Constraints() #创建一个新的约束信息
  116. constraints.position_constraints.append(position_constraint)
  117. return constraints
  118. #TODO move_p_flexible 转点规划
  119. def move_p_flexible(self, point, points, trajectory, trajectory_with_type, a=1, v=1):
  120. self.arm.set_max_acceleration_scaling_factor(a)
  121. self.arm.set_max_velocity_scaling_factor(v)
  122. rrr = 0.2 #初始允许半径 20cm, 点到点转焊缝,可适当放宽初始半径
  123. er = 0
  124. if trajectory:
  125. #起点位置设置为规划组最后一个点,即上一次移动的终点
  126. state = self.arm.get_current_state()
  127. state.joint_state.position = trajectory[-1].joint_trajectory.points[-1].positions
  128. path_constraints = self.create_path_constraints2(points[-1], point, rrr)#将当前的点和输入的点(焊缝的起始点)做圆柱轨迹约束
  129. else:
  130. #刚开始规划 起点位置设定为当前状态 按理来说是home点
  131. self.go_home()
  132. self.home_pose = self.get_now_pose()
  133. state = self.arm.get_current_state()
  134. path_constraints = self.create_path_constraints2(self.home_pose, point, rrr)#将当前的点和输入的点(焊缝的起始点)做圆柱轨迹约束
  135. self.arm.set_path_constraints(path_constraints)
  136. self.arm.set_pose_target(point, self.end_effector_link)
  137. self.arm.set_start_state(state) #起点位置设置为规划组最后一个点 或者当前状态(第一个点时)
  138. #尝试规划次数共10次,带约束规划5次仍失败取消约束重新规划5次
  139. b = 10
  140. for i in range(b):
  141. traj = self.arm.plan() #调用plan进行规划(OMPL)
  142. error = traj[3]
  143. if error.val == moveit_msgs.msg._MoveItErrorCodes.MoveItErrorCodes.SUCCESS:
  144. trajj = traj[1] #取出规划的信息
  145. rospy.loginfo("规划完成! 正在检查移动轨迹有效性...")
  146. error_c, limit_margin = check.check_joint_positions(trajj)
  147. if not error_c:
  148. rospy.loginfo("本次移动OK")
  149. rospy.loginfo("*******************")
  150. trajj_with_type = mark_the_traj(trajj,"during-p", welding_sequence)
  151. trajectory_with_type.append(trajj_with_type)
  152. points.append(point)
  153. trajectory.append(trajj)
  154. break
  155. else:
  156. rospy.loginfo("check failed! 移动轨迹无效")
  157. rospy.loginfo("移动轨迹检查失败-开始第{}次重新规划".format(i+1))
  158. self.arm.clear_path_constraints()
  159. rrr += 0.2 #每次增加20厘米半径
  160. rospy.loginfo("R值: {}".format(rrr))
  161. if trajectory:
  162. path_constraints = self.create_path_constraints2(points[-1], point, rrr)#将最后一个点和输入的点(焊缝的起始点)做圆柱轨迹约束
  163. else:
  164. path_constraints = self.create_path_constraints2(self.home_pose, point, rrr)#将最后一个点和起点(焊缝的起始点)做圆柱轨迹约束
  165. self.arm.set_path_constraints(path_constraints)
  166. if(i >= (b-5)):
  167. rospy.loginfo("约束移动规划尝试失败,取消约束重新规划")
  168. self.arm.clear_path_constraints()
  169. if(i == (b-1)):
  170. rospy.loginfo("所有移动规划尝试失败,焊缝起点不可达!")
  171. er = 1
  172. break
  173. else:
  174. er = 1
  175. rospy.loginfo("移动规划失败,焊缝起点不可达!")
  176. break
  177. #清除约束
  178. self.arm.clear_path_constraints()
  179. return points, trajectory, trajectory_with_type, er
  180. #TODO move_pl 路径约束
  181. def create_path_constraints(self, start_point, end_point):
  182. #计算起点指向终点的向量
  183. vector = np.array([end_point[0]- start_point[0], end_point[1]- start_point[1], end_point[2]- start_point[2]])
  184. height = np.linalg.norm(vector) + 0.002
  185. radius = 0.01
  186. constraints = Constraints()
  187. # 位置约束
  188. position_constraint = PositionConstraint()
  189. position_constraint.header.frame_id = "base_link"
  190. position_constraint.link_name = self.end_effector_link
  191. position_constraint.target_point_offset = Vector3(0, 0, 0)
  192. #构建 shape_msgs/SolidPrimitive 消息
  193. bounding_volume = SolidPrimitive()
  194. bounding_volume.type = SolidPrimitive.CYLINDER
  195. # bounding_volume.dimensions = [0.003,1]
  196. bounding_volume.dimensions = [height, radius]
  197. #构建 geometry_msgs/Pose 消息,用于指定圆柱体在空间中的位置和姿态
  198. pose = Pose()
  199. pose.position.x = start_point[0] + vector[0] / 2
  200. pose.position.y = start_point[1] + vector[1] / 2
  201. pose.position.z = start_point[2] + vector[2] / 2
  202. # 计算圆柱体的旋转矩阵
  203. z_axis = np.array([0, 0, 1])
  204. axis = np.cross(z_axis, vector)
  205. angle = np.arccos(np.dot(z_axis, vector) / np.linalg.norm(vector))
  206. q = tf.transformations.quaternion_about_axis(angle, axis)
  207. pose.orientation.x = q[0]
  208. pose.orientation.y = q[1]
  209. pose.orientation.z = q[2]
  210. pose.orientation.w = q[3]
  211. position_constraint.constraint_region.primitives.append(bounding_volume)
  212. position_constraint.constraint_region.primitive_poses.append(pose)
  213. position_constraint.weight = 1.0
  214. # 角度约束
  215. # target_pose = Pose()
  216. # target_pose.orientation.x = start_point[3]
  217. # target_pose.orientation.y = start_point[4]
  218. # target_pose.orientation.z = start_point[5]
  219. # target_pose.orientation.w = start_point[6]
  220. # Orientation_Constraint = OrientationConstraint()
  221. # Orientation_Constraint.link_name = self.end_effector_link
  222. # Orientation_Constraint.header.frame_id = "base_link"
  223. # Orientation_Constraint.orientation = target_pose.orientation
  224. # Orientation_Constraint.absolute_x_axis_tolerance = 0.01
  225. # Orientation_Constraint.absolute_y_axis_tolerance = 0.01
  226. # Orientation_Constraint.absolute_z_axis_tolerance = 0.01
  227. # Orientation_Constraint.weight = 1.0 # 权重,硬约束
  228. constraints.position_constraints.append(position_constraint)
  229. # constraints.orientation_constraints.append(Orientation_Constraint)
  230. return constraints
  231. #TODO move_pl 焊缝规划,规划当前点(焊缝起点)和焊缝终点之间的路径
  232. def move_pl(self, point, points, trajectory, trajectory_with_type, a=1, v=1):
  233. self.arm.set_max_acceleration_scaling_factor(a)
  234. self.arm.set_max_velocity_scaling_factor(v)
  235. #move_p规划成功,则move_p规划路径中的最后一个关节轨迹点为move_pl的起点
  236. if trajectory:
  237. state = self.arm.get_current_state()
  238. #路径中的最后一个关节轨迹点
  239. state.joint_state.position = trajectory[-1].joint_trajectory.points[-1].positions
  240. self.arm.set_start_state(state)
  241. else:
  242. """
  243. 第一次规划超时(Time_out),但并未返回Error_code;此时move_p并不会返回任何路径点信息
  244. 到points列表中,此时机器人应还处在home点位置,在此将home点直接添加到points列表中,与
  245. 焊缝终点做路径约束,并规划路径 (虽然不再报错继续执行,但该条焊缝仍规划失败)
  246. """
  247. points.append(self.home_pose)
  248. self.arm.set_pose_target(point, self.end_effector_link) #设定目标点为焊缝终点
  249. #创建路径约束
  250. path_constraints = self.create_path_constraints(points[-1], point) #将最后一个点(应为起始点)和输入的点(焊缝的起始点)做圆柱轨迹约束
  251. self.arm.set_path_constraints(path_constraints)#设定约束
  252. traj = self.arm.plan()
  253. error = traj[3]
  254. if error.val == moveit_msgs.msg._MoveItErrorCodes.MoveItErrorCodes.SUCCESS:
  255. rospy.loginfo("本次焊缝规划 OK")
  256. rospy.loginfo("*******************")
  257. trajj = traj[1] #取出规划的信息
  258. trajj_with_type = mark_the_traj(trajj, "during-l", welding_sequence)
  259. trajj_with_type.points[-len(trajj.joint_trajectory.points)].type = "start"
  260. trajj_with_type.points[-1].type = "end"
  261. points.append(point)
  262. trajectory.append(trajj)
  263. trajectory_with_type.append(trajj_with_type)
  264. else:
  265. rospy.loginfo("本次焊缝规划失败")
  266. points.pop() #将本条焊缝的起点从规划中删除
  267. # 同样第一次move_p提示timeout, trajectory中同样不会有路径信息
  268. if trajectory:
  269. trajectory.pop()
  270. trajectory_with_type.pop()
  271. self.hf_fail.append(welding_sequence[self.hf_num]) #将焊缝添加到失败列表
  272. self.arm.clear_path_constraints()
  273. self.hf_num = self.hf_num + 1 #焊缝计数
  274. return points, trajectory, trajectory_with_type
  275. # 暂未使用
  276. def move_pl_check(self, point, points, trajectory, trajectory_with_type, a=1, v=1):
  277. self.arm.set_max_acceleration_scaling_factor(a)
  278. self.arm.set_max_velocity_scaling_factor(v)
  279. #重新规划起点次数
  280. a=10
  281. for j in range(a):
  282. if trajectory:
  283. state = self.arm.get_current_state()
  284. state.joint_state.position = trajectory[-1].joint_trajectory.points[-1].positions
  285. self.arm.set_start_state(state)
  286. self.arm.set_pose_target(point, self.end_effector_link)
  287. path_constraints = self.create_path_constraints(points[-1], point)
  288. self.arm.set_path_constraints(path_constraints)
  289. #当前起点规划次数
  290. b=10
  291. for i in range(b):
  292. traj = self.arm.plan()
  293. error = traj[3]
  294. if error.val == moveit_msgs.msg._MoveItErrorCodes.MoveItErrorCodes.SUCCESS:
  295. trajj = traj[1] #取出规划的信息
  296. rospy.loginfo("正在检查焊缝轨迹有效性...")
  297. error_c,limit_margin = check.check_joint_positions(trajj)
  298. if not error_c:
  299. rospy.loginfo("本次焊缝规划OK")
  300. rospy.loginfo("*******************")
  301. break
  302. if not limit_margin or i == b-1:
  303. prepoint = points.pop()
  304. trajectory.pop()
  305. trajectory_with_type.pop()
  306. #清除约束
  307. self.arm.clear_path_constraints()
  308. points, trajectory, trajectory_with_type, er1 = self.move_p_flexible(prepoint, points, trajectory, trajectory_with_type)
  309. break
  310. rospy.loginfo("The {}-{}th replanning".format(j,i+1))
  311. if not error_c:
  312. break
  313. if error_c:
  314. rospy.loginfo("本次焊缝规划失败")
  315. rospy.loginfo("*******************")
  316. self.hf_fail.append(welding_sequence[self.hf_num])
  317. self.arm.clear_path_constraints()
  318. self.hf_num = self.hf_num + 1#焊缝计数
  319. trajj_with_type = mark_the_traj(trajj, "during-l", welding_sequence)
  320. trajj_with_type.points[-len(trajj.joint_trajectory.points)].type = "start"
  321. trajj_with_type.points[-1].type = "end"
  322. points.append(point)
  323. trajectory.append(trajj)
  324. trajectory_with_type.append(trajj_with_type)
  325. return points, trajectory, trajectory_with_type
  326. #TODO go_home
  327. @decorator_time
  328. def go_home(self, a=1, v=1):
  329. rospy.loginfo("go_home start")
  330. self.arm.set_max_acceleration_scaling_factor(a)
  331. self.arm.set_max_velocity_scaling_factor(v)
  332. self.arm.set_named_target('home')
  333. rospy.loginfo("get_home end")
  334. self.arm.go()
  335. rospy.loginfo("go_home end")
  336. # rospy.sleep(1)
  337. #TODO go_home_justplan
  338. def go_home_justplan(self, trajectory, trajectory_with_type, a=1, v=1):
  339. self.arm.set_max_acceleration_scaling_factor(a)
  340. self.arm.set_max_velocity_scaling_factor(v)
  341. state = self.arm.get_current_state()
  342. state.joint_state.position = trajectory[-1].joint_trajectory.points[-1].positions
  343. self.arm.set_start_state(state)
  344. self.arm.set_named_target('home')
  345. traj = self.arm.plan()
  346. trajj = traj[1]
  347. traj_with_type = mark_the_traj(trajj, "go-home", welding_sequence)
  348. trajectory.append(trajj)
  349. trajectory_with_type.append(traj_with_type)
  350. return trajectory, trajectory_with_type
  351. #TODO path_planning
  352. @decorator_time
  353. def path_planning(self, folder_path, gohome=True):
  354. file_path_result = os.path.join(folder_path, 'result.txt')
  355. all_data = process_welding_data(file_path_result)
  356. err = 0
  357. points, trajectory, trajectory_with_type = [],[],[]
  358. for i in range(len(all_data)):
  359. rospy.loginfo("共读取到%d条焊缝,开始规划第%d条", len(all_data), i+1)
  360. start_point = all_data[i][0]
  361. end_point = all_data[i][1]
  362. q1 = all_data[i][2]
  363. q2 = all_data[i][3]
  364. point11 = [start_point[0]/1000, start_point[1]/1000, start_point[2]/1000, q1[0], q1[1], q1[2], q1[3]]
  365. points, trajectory, trajectory_with_type, err = self.move_p_flexible(point11, points, trajectory, trajectory_with_type)
  366. # 焊缝起点不可达 则跳过此次焊缝和移动的规划 并将焊缝添加到失败列表
  367. if err == 1:
  368. self.hf_fail.append(welding_sequence[self.hf_num])
  369. self.hf_num = self.hf_num+1 # 焊缝计数
  370. continue
  371. point22 = [end_point[0]/1000, end_point[1]/1000, end_point[2]/1000, q2[0], q2[1], q2[2], q2[3]]
  372. points, trajectory, trajectory_with_type = self.move_pl(point22, points, trajectory, trajectory_with_type, v=speed_v)
  373. rospy.loginfo("第%d条焊缝规划完毕", i+1)
  374. rospy.loginfo("*******************")
  375. if gohome:
  376. points, trajectory, trajectory_with_type, err = self.move_p_flexible(self.home_pose, points, trajectory, trajectory_with_type, v=speed_v)
  377. trajectory,trajectory_with_type = self.go_home_justplan(trajectory,trajectory_with_type)
  378. traj_merge = merge_trajectories(trajectory)
  379. trajectory_with_type_merge = merge_trajectories_with_type(trajectory_with_type)
  380. rospy.loginfo("All of The trajectory Plan successfully")
  381. return trajectory, traj_merge, trajectory_with_type_merge
  382. ###########################################################class end#############################################################
  383. def process_welding_data(filename):
  384. all_data = [] # 用来存储每一行处理后的数据
  385. with open(filename, 'r') as file:
  386. for line in file:
  387. parts = line.strip().split('/')
  388. coordinates_and_poses = [part.split(',') for part in parts[1:]]
  389. start_point = tuple(map(float, coordinates_and_poses[0][:3])) # 使用元组以避免修改
  390. end_point = tuple(map(float, coordinates_and_poses[1][:3]))
  391. q1 = tuple(map(float, coordinates_and_poses[2][:4]))
  392. q2 = tuple(map(float, coordinates_and_poses[3][:4]))
  393. # 收集每行处理后的数据
  394. all_data.append((start_point, end_point, q1, q2))
  395. return all_data
  396. #TODO mark_the_traj 标记轨迹类型(during-p, during-l, go-home)
  397. def mark_the_traj(traj, TYPE, SEQUENCE):
  398. traj_with_type = JointTrajectory_ex()
  399. traj_with_type.header = traj.joint_trajectory.header
  400. traj_with_type.joint_names = traj.joint_trajectory.joint_names
  401. traj_with_type.points = [
  402. JointTrajectoryPoint_ex(
  403. positions = point.positions,
  404. velocities = point.velocities,
  405. accelerations = point.accelerations,
  406. effort = point.effort,
  407. type = TYPE,
  408. sequence = SEQUENCE
  409. ) for point in traj.joint_trajectory.points
  410. ]
  411. return traj_with_type
  412. #TODO merge_trajectories 合并所有关节轨迹点
  413. def merge_trajectories(trajectories):
  414. if not trajectories:
  415. return None
  416. # 创建一个新的 JointTrajectory 对象
  417. merged_trajectory = JointTrajectory()
  418. merged_trajectory.header = trajectories[0].joint_trajectory.header
  419. merged_trajectory.joint_names = trajectories[0].joint_trajectory.joint_names
  420. # 初始化时间累加器
  421. last_time_from_start = rospy.Duration(0)
  422. # 合并所有 trajectories 的 points
  423. for traj in trajectories:
  424. for point in traj.joint_trajectory.points:
  425. # 创建新的轨迹点
  426. new_point = deepcopy(point)
  427. # 累加时间
  428. new_point.time_from_start += last_time_from_start
  429. merged_trajectory.points.append(new_point)
  430. # 更新时间累加器为当前轨迹的最后一个点的时间
  431. if traj.joint_trajectory.points:
  432. last_time_from_start = traj.joint_trajectory.points[-1].time_from_start + last_time_from_start
  433. return merged_trajectory
  434. #TODO merge_trajectories_with_type 合并所有带焊缝起始点标记的关节轨迹点
  435. def merge_trajectories_with_type(trajectory_with_type):
  436. if not trajectory_with_type:
  437. return None
  438. # 创建一个新的 JointTrajectory 对象
  439. merged_trajectory_with_type = JointTrajectory_ex()
  440. merged_trajectory_with_type.header = trajectory_with_type[0].header
  441. merged_trajectory_with_type.joint_names = trajectory_with_type[0].joint_names
  442. # 初始化时间累加器
  443. last_time_from_start = rospy.Duration(0)
  444. # 合并所有 trajectories 的 points
  445. for traj in trajectory_with_type:
  446. for point in traj.points:
  447. # 创建新的轨迹点
  448. new_point = deepcopy(point)
  449. # 累加时间
  450. new_point.time_from_start += last_time_from_start
  451. merged_trajectory_with_type.points.append(new_point)
  452. # 更新时间累加器为当前轨迹的最后一个点的时间
  453. if traj.points:
  454. last_time_from_start = traj.points[-1].time_from_start + last_time_from_start
  455. return merged_trajectory_with_type
  456. def pub_trajectories(trajectory_with_type_merge):
  457. pub = rospy.Publisher("/joint_path", JointTrajectory_ex, queue_size=5)
  458. count = 1
  459. rate = rospy.Rate(1)
  460. rospy.loginfo("正在发布轨迹信息..")
  461. while not rospy.is_shutdown():
  462. #轨迹接受完毕,关闭当前发布
  463. sign_traj_accepted = str(rospy.get_param("sign_traj_accepted"))
  464. if sign_traj_accepted == "1":
  465. rospy.set_param("sign_traj_accepted",0)
  466. break
  467. pub.publish(trajectory_with_type_merge)
  468. # rospy.loginfo("发布计数,count = %d",count)
  469. # count += 1
  470. rate.sleep()
  471. class py_msgs():
  472. fial = []
  473. shun_xv = []
  474. class point():
  475. xyz_list = []
  476. type = []
  477. # ROS2PY_msgs 将规划后的轨迹信息打包成json格式发送到redis
  478. def ROS2PY_msgs(msgs, m_sr):
  479. for i in range(len(msgs.points)):
  480. py_msgs.point.xyz_list.append(msgs.points[i].positions)
  481. py_msgs.point.type.append(msgs.points[i].type)
  482. py_msgs.fail = m_sr.hf_fail.copy()
  483. py_msgs.shun_xv = msgs.points[0].sequence.copy()
  484. # for i in range(len(py_msgs.point.type)):
  485. # print(py_msgs.point.xyz_list[i])
  486. # print(py_msgs.point.type[i])
  487. message = {
  488. 'positions': py_msgs.point.xyz_list, # 规划路径点结果
  489. 'flags': py_msgs.point.type, # 规划路径点的类型,焊接点移动点
  490. 'weld_order': py_msgs.shun_xv, # 规划路径顺序
  491. 'failed': py_msgs.fail, # 规划路径失败的焊缝
  492. }
  493. return json.dumps(message)
  494. # for i in range(len(py_msgs.point.type)):
  495. # moveit_server.move_j(py_msgs.point.xyz_list[i])
  496. # #input("任意键继续")
  497. #TODO get_valid_input 监听用户输入
  498. def get_valid_input(factor, default):
  499. while True:
  500. user_input = input(factor)
  501. if user_input == "":
  502. return default
  503. try:
  504. value = float(user_input)
  505. if 0 < value <= 1:
  506. return value
  507. else:
  508. rospy.logerr("缩放因子必须在(0, 1]范围内,请重新输入!")
  509. except ValueError:
  510. rospy.logerr("输入值无效,请根据提示重新输入!")
  511. # TODO get_uesr_input 获取用户输入
  512. def get_user_input():
  513. """获取用户输入的速度和加速度缩放因子,并在控制台中打印信息和错误提示"""
  514. DEFUALT_V = 1.0
  515. DEFUALT_A = 1.0
  516. try:
  517. termios.tcflush(sys.stdin, termios.TCIFLUSH) #清空输入缓存
  518. rospy.loginfo("输入缓存区已清空!")
  519. vv = get_valid_input("请输入速度缩放因子(0-1, 默认为1): ", DEFUALT_V)
  520. #a=get_valid_input("请输入加速度缩放因子(0-1, 默认为1): ", DEFUALT_A)
  521. #rospy.loginfo(f"用户输入的速度缩放因子为{vv}")
  522. return vv
  523. except Exception as e:
  524. rospy.logerr(f"发生错误:{e}")
  525. def ROS2_msgs(msgs, m_sr):
  526. for i in range(len(msgs.points)):
  527. py_msgs.point.xyz_list.append(msgs.points[i].positions)
  528. f_p = os.path.join(folder_path, 'outtt.txt')
  529. with open(f_p, 'w') as file:
  530. for point in py_msgs.point.xyz_list:
  531. file.write(' '.join(str(value) for value in point) + "\n")
  532. if __name__ =="__main__":
  533. folder_path = rospy.get_param("folder_path")
  534. rospy.init_node('moveit_control_server', anonymous=False)
  535. moveit_server = MoveIt_Control(is_use_gripper=False)
  536. welding_sequence = rospy.get_param('welding_sequence')
  537. speed_v = 1.0
  538. # speed_v=get_user_input()
  539. # rospy.loginfo(f"用户输入的速度缩放因子为{speed_v}")
  540. trajectory, trajectory_merge, trajectory_with_type_merge = moveit_server.path_planning(folder_path)
  541. #ROS2_msgs(trajectory_with_type_merge,moveit_server)
  542. #write_ee(trajectory_with_type_merge, moveit_server)
  543. moveit_server.arm.execute(trajectory_merge)
  544. print(f"本次规划失败焊缝序号:{moveit_server.hf_fail}")
  545. #使用redis发布规划后的轨迹信息
  546. #message = ROS2PY_msgs(trajectory_with_type_merge,moveit_server)
  547. #publisher = Publisher()
  548. #publisher.pub_plan_result(message)
  549. rospy.set_param("sign_control",0)