RobotData.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. import enum
  2. import time
  3. import message_pb2 as message
  4. from mqtt_async import MqttAsync
  5. import google.protobuf.json_format as jtf
  6. from dijkstra.Map import DijikstraMap,SpaceNode,StreetNode
  7. import uuid
  8. from auto_test import TestCount
  9. import random
  10. import math
  11. class ActType(enum.Enum):
  12. eReady=0
  13. eRotation=1
  14. eHorizon=2
  15. eVertical=3
  16. eMPC=4
  17. eClampOpen=5
  18. eClampClose=6
  19. class TimeStatu:
  20. def __init__(self, statu=None, timeout=3):
  21. self.statu = statu
  22. self.time = time.time()
  23. self.timeout_ms = timeout
  24. def timeout(self):
  25. tm = time.time()
  26. return tm - self.time > self.timeout_ms or self.statu == None
  27. class Robot(MqttAsync):
  28. def __init__(self, name=""):
  29. MqttAsync.__init__(self)
  30. self.timedRobotStatu_ = TimeStatu(message.RobotStatu, 0)
  31. self.timedNavStatu_ = TimeStatu(message.NavStatu, 0)
  32. self.dataTopic_ = {}
  33. self.messageArrivedSignal = None
  34. self.currentNavData_ = None
  35. self.navCmdTopic_ = None
  36. self.currentNavPathNodes_ = None
  37. self.currentNavPath_ = None
  38. self.pathColor_ = [1, 1, 0]
  39. self.robotColor_ = [0.7, 0.2, 0.3] # agv当前颜色
  40. self.name_ = name
  41. self.begId_="------"
  42. self.targetId_="------"
  43. self.autoTest_=False
  44. self.l_ = 0.8 # 轮长
  45. self.L_ = 1.3 # 轴距
  46. self.W_ = 2.5 # 宽
  47. def Color(self):
  48. if self.IsMainModeStatu():
  49. return [0, 0, 0]
  50. return self.robotColor_
  51. def IsMainAgv(self):
  52. if self.timedNavStatu_.timeout() == False:
  53. if self.timedNavStatu_.statu.main_agv == True:
  54. return True
  55. return False
  56. def IsMainModeStatu(self):
  57. if self.IsMainAgv():
  58. if self.timedNavStatu_.timeout() == False:
  59. if self.timedNavStatu_.statu.move_mode == 2:
  60. return True
  61. return False
  62. def SetSubDataTopic(self, match: dict, messageSignal=None):
  63. self.dataTopic_ = match
  64. self.messageArrivedSignal = messageSignal
  65. for item in match.items():
  66. [topic, _] = item
  67. self.subscribe(topic, self.on_message)
  68. def SetCmdTopic(self, topic):
  69. self.navCmdTopic_ = topic
  70. def SetColor(self, pathColor, robotColor):
  71. self.pathColor_ = pathColor
  72. self.robotColor_ = robotColor
  73. def ResetPose(self, agv: message.RobotStatu):
  74. self.timedRobotStatu_ = TimeStatu(agv, 0.5)
  75. def ResetNavStatu(self, statu: message.NavStatu):
  76. self.timedNavStatu_ = TimeStatu(statu, 0.5)
  77. def on_message(self, client, userdata, msg):
  78. topic = msg.topic
  79. if self.dataTopic_.get(topic) is not None:
  80. dtype = self.dataTopic_[topic]
  81. if dtype == message.RobotStatu.__name__:
  82. proto = message.RobotStatu()
  83. jtf.Parse(msg.payload.decode(), proto)
  84. self.ResetPose(proto)
  85. if dtype == message.NavStatu.__name__:
  86. self.last_running = self.IsNavigating()
  87. proto = message.NavStatu()
  88. jtf.Parse(msg.payload.decode(), proto)
  89. self.ResetNavStatu(proto)
  90. if self.last_running == True and self.IsNavigating() == False:
  91. self.currentNavPathNodes_ = None
  92. self.currentNavPath_ = None
  93. if self.messageArrivedSignal is not None:
  94. self.messageArrivedSignal()
  95. def MpcSelectTraj(self):
  96. traj = []
  97. if self.timedNavStatu_.timeout() == False:
  98. nav = self.timedNavStatu_.statu
  99. for pose2d in nav.selected_traj.poses:
  100. traj.append([pose2d.x, pose2d.y, pose2d.theta])
  101. return traj
  102. def MpcPredictTraj(self):
  103. traj = []
  104. if self.timedNavStatu_.timeout() == False:
  105. nav = self.timedNavStatu_.statu
  106. for pose2d in nav.predict_traj.poses:
  107. traj.append([pose2d.x, pose2d.y, pose2d.theta])
  108. return traj
  109. def Connected(self):
  110. return self.timedNavStatu_.timeout() == False and self.timedRobotStatu_.timeout() == False
  111. def IsNavigating(self):
  112. return not self.ActionType()==ActType.eReady
  113. '''if self.timedNavStatu_.timeout() == False:
  114. key = self.timedNavStatu_.statu.key
  115. if key == "" or key == None:
  116. return False
  117. return True'''
  118. def GeneratePath(self, begID, endID):
  119. self.currentNavPathNodes_ = DijikstraMap().GetShortestPath(begID, endID)
  120. self.currentNavPath_ = DijikstraMap().CreatePath(self.currentNavPathNodes_, 0.5)
  121. if self.currentNavPathNodes_ is not None and self.currentNavPath_ is not None:
  122. self.begId_=begID
  123. self.targetId_=endID
  124. return True
  125. return False
  126. def PositionId(self):
  127. if self.timedRobotStatu_.timeout():
  128. return None
  129. x=self.timedRobotStatu_.statu.x
  130. y=self.timedRobotStatu_.statu.y
  131. djks_map = DijikstraMap()
  132. [label, pt] = djks_map.findNeastNode([x, y])
  133. return [label,pt]
  134. '''
  135. 阻塞直到导航完成
  136. '''
  137. def Navigatting(self, begId, targetId):
  138. print("nav")
  139. self.GeneratePath(begId, targetId)
  140. self.ExecPathNodes()
  141. #self.ExecNavtask()
  142. while self.IsNavigating() == True:
  143. '''if self.Connected() == False:
  144. print("robot disconnected cancel task")
  145. self.CancelNavTask()
  146. return False'''
  147. time.sleep(0.5)
  148. print(" Nav completed!!!")
  149. return True
  150. def TestNavClampOnce(self,begId,targetId):
  151. if self.IsClampClosed()==False:
  152. print("closed")
  153. if self.ClampClose()==False:
  154. return False
  155. if self.Navigatting(begId,targetId):
  156. if self.ClampOpen():
  157. TestCount().loadCountAdd()
  158. return True
  159. return False
  160. def AutoTestNavClamp(self,begId,targetId):
  161. beg=begId
  162. target=targetId
  163. while self.autoTest_:
  164. if self.TestNavClampOnce(beg,target)==False:
  165. print(" quit auto Test")
  166. break
  167. print("1111")
  168. posInfo=self.PositionId()
  169. if posInfo is not None:
  170. [label,pt]=posInfo
  171. beg=label
  172. print("beg",beg)
  173. node=DijikstraMap().GetVertex(beg)
  174. if node is not None:
  175. if isinstance(node,(SpaceNode)):
  176. target="O"
  177. if isinstance(node,(StreetNode)):
  178. end_nodes=["E","B","C","D"]
  179. id=random.randint(0,1000)%4
  180. target=end_nodes[id]
  181. print("3333",target)
  182. print(" Next nav clamp cmd,%s to %s"%(beg,target))
  183. def ActionType(self):
  184. if self.timedNavStatu_.timeout() == False:
  185. runningStatu=self.timedNavStatu_.statu
  186. if runningStatu.statu==0:
  187. return ActType.eReady
  188. if runningStatu.statu==1:
  189. return ActType.eRotation
  190. if runningStatu.statu==2:
  191. return ActType.eHorizon
  192. if runningStatu.statu==3:
  193. return ActType.eVertical
  194. if runningStatu.statu==4:
  195. return ActType.eMPC
  196. if runningStatu.statu==5:
  197. return ActType.eClampOpen
  198. if runningStatu.statu==6:
  199. return ActType.eClampClose
  200. else:
  201. return ActType.eReady
  202. def ExecNavtask(self):
  203. if self.navCmdTopic_ == None:
  204. print("Robot has not set nav cmd topic")
  205. return False
  206. if not self.ActionType()==ActType.eReady:
  207. print(" robot is navigating ,key:%s" % (self.timedNavStatu_.statu.key))
  208. return False
  209. cmd = None
  210. if self.currentNavPathNodes_ is not None and self.timedRobotStatu_.timeout() == False:
  211. statu = self.timedRobotStatu_.statu
  212. if statu is not None:
  213. cmd = DijikstraMap().CreateNavCmd([statu.x, statu.y, statu.theta], self.currentNavPathNodes_)
  214. else:
  215. print("current path is none")
  216. return False
  217. if cmd is None:
  218. print("Nav cmd is None")
  219. return False
  220. published=False
  221. while self.IsNavigating() == False:
  222. if not self.ActionType() == ActType.eReady:
  223. published=True
  224. if published==False:
  225. self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
  226. time.sleep(1)
  227. print("send nav cmd completed!!!")
  228. return True
  229. def ExecPathNodes(self,autoDirect=False):
  230. if self.navCmdTopic_ == None:
  231. print("Robot has not set nav cmd topic")
  232. return False
  233. if not self.ActionType()==ActType.eReady:
  234. print(" robot is navigating ,key:%s" % (self.timedNavStatu_.statu.key))
  235. return False
  236. cmd = message.NavCmd()
  237. cmd.action=6
  238. if self.currentNavPathNodes_ is not None and self.timedRobotStatu_.timeout() == False:
  239. statu = self.timedRobotStatu_.statu
  240. if statu is not None:
  241. newAction=message.NewAction()
  242. limitMPC_v=message.SpeedLimit()
  243. limitRotate=message.SpeedLimit()
  244. limAdjustV=message.SpeedLimit()
  245. limitAdjustH=message.SpeedLimit()
  246. limitMPC_v.min=0.05
  247. limitMPC_v.max=1.2
  248. limitRotate.min=3*math.pi/180.0
  249. limitRotate.max=25*math.pi/180.0
  250. limAdjustV.min=0.03
  251. limAdjustV.max=0.3
  252. limitAdjustH.min=0.03
  253. limitAdjustH.max=0.3
  254. count=0
  255. size=len(self.currentNavPathNodes_)
  256. for i in range(size):
  257. node=self.currentNavPathNodes_[i]
  258. pose=message.Pose2d()
  259. accuracy=message.Pose2d()
  260. pose.x=node.x_
  261. pose.y=node.y_
  262. if i+1<size:
  263. next=self.currentNavPathNodes_[i+1]
  264. vector = [next.x_ - node.x_, next.y_ - node.y_]
  265. dx = vector[0]
  266. dy = vector[1]
  267. yaw = math.asin(dy / math.sqrt(dx * dx + dy * dy))
  268. if yaw >= 0:
  269. if dx < 0:
  270. yaw = math.pi - yaw
  271. if yaw < 0:
  272. if dx < 0:
  273. yaw = -math.pi - yaw
  274. pose.theta=yaw
  275. else:
  276. pose.theta=0
  277. if count==size-1:
  278. accuracy.x=0.02
  279. accuracy.y=0.02
  280. accuracy.theta=0.5*math.pi/(180.0)
  281. else:
  282. accuracy.x=0.05
  283. accuracy.y=0.1
  284. accuracy.theta=3*math.pi/180.0
  285. pathNode=message.PathNode()
  286. pathNode.pose.CopyFrom(pose)
  287. pathNode.accuracy.CopyFrom(accuracy)
  288. newAction.type=4
  289. if autoDirect:
  290. newAction.type=3
  291. newAction.pathNodes.add().CopyFrom(pathNode)
  292. newAction.NodeVelocityLimit.CopyFrom(limitMPC_v)
  293. newAction.NodeAngularLimit.CopyFrom(limitRotate)
  294. newAction.adjustVelocitylimit.CopyFrom(limAdjustV)
  295. newAction.adjustHorizonLimit.CopyFrom(limitAdjustH)
  296. cmd.newActions.add().CopyFrom(newAction)
  297. count+=1
  298. else:
  299. print("statu is None")
  300. return False
  301. else:
  302. print("current path is none")
  303. return False
  304. if cmd is None:
  305. print("Nav cmd is None")
  306. return False
  307. print(cmd)
  308. published=False
  309. while self.IsNavigating() == False:
  310. if not self.ActionType() == ActType.eReady:
  311. published=True
  312. if published==False:
  313. self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
  314. time.sleep(1)
  315. print("send nav cmd completed!!!")
  316. return True
  317. def SwitchMoveMode(self, mode, wheelbase):
  318. if self.IsMainAgv() == False:
  319. print(" this agv is single can not switch mode")
  320. return False
  321. cmd = message.NavCmd()
  322. if mode == 2:
  323. cmd.wheelbase = wheelbase
  324. cmd.action = 4
  325. if mode == 1:
  326. cmd.action = 5
  327. loop=3
  328. while loop>0:
  329. if mode == 2:
  330. if self.IsMainModeStatu():
  331. return True
  332. if mode == 1:
  333. if self.IsMainModeStatu() == False:
  334. return True
  335. self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
  336. loop-=1
  337. time.sleep(0.5)
  338. return False
  339. def IsClampClosed(self):
  340. if self.timedRobotStatu_.timeout() == False:
  341. if self.IsMainModeStatu():
  342. clamp = self.timedRobotStatu_.statu.agvStatu.clamp
  343. clamp_other = self.timedRobotStatu_.statu.agvStatu.clamp_other
  344. return (clamp == 1 and clamp_other == 1)
  345. else:
  346. return self.timedRobotStatu_.statu.agvStatu.clamp == 1
  347. return False
  348. def IsClampRunning(self):
  349. if self.timedRobotStatu_.timeout() == False:
  350. if self.IsMainModeStatu():
  351. clamp = self.timedRobotStatu_.statu.agvStatu.clamp
  352. clamp_other = self.timedRobotStatu_.statu.agvStatu.clamp_other
  353. return (clamp == 0 or clamp_other == 0)
  354. else:
  355. return self.timedRobotStatu_.statu.agvStatu.clamp == 0
  356. return False
  357. def IsClampOpened(self):
  358. if self.timedRobotStatu_.timeout() == False:
  359. if self.IsMainModeStatu():
  360. clamp = self.timedRobotStatu_.statu.agvStatu.clamp
  361. clamp_other = self.timedRobotStatu_.statu.agvStatu.clamp_other
  362. return (clamp == 2 and clamp_other == 2)
  363. else:
  364. return self.timedRobotStatu_.statu.agvStatu.clamp == 2
  365. return False
  366. def ClampClose(self):
  367. if self.IsClampClosed() == True:
  368. print("clamp closed")
  369. return True
  370. cmd = message.NavCmd()
  371. key = str(uuid.uuid4())
  372. cmd.key = (key)
  373. act = message.Action()
  374. act.type = 3
  375. cmd.actions.add().CopyFrom(act)
  376. published=False
  377. while self.IsClampClosed()==False:
  378. if self.ActionType()==ActType.eClampClose:
  379. published=True
  380. if published==False:
  381. self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
  382. time.sleep(0.5)
  383. return True
  384. def ClampOpen(self):
  385. if self.IsClampOpened() == True:
  386. print("clamp opended")
  387. return True
  388. cmd = message.NavCmd()
  389. key = str(uuid.uuid4())
  390. cmd.key = (key)
  391. act = message.Action()
  392. act.type = 4
  393. cmd.actions.add().CopyFrom(act)
  394. published=False
  395. while self.IsClampOpened()==False:
  396. if self.ActionType()==ActType.eClampOpen:
  397. published=True
  398. if published==False:
  399. self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
  400. time.sleep(0.5)
  401. return True
  402. def CancelNavTask(self):
  403. cmd = message.NavCmd()
  404. cmd.action = 3
  405. while self.IsNavigating() == True:
  406. self.publish(self.navCmdTopic_, jtf.MessageToJson(cmd))
  407. time.sleep(1)
  408. print(" Cancel task completed!!!")
  409. return True