RobotData.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. import copy
  2. import enum
  3. import time
  4. import message_pb2 as message
  5. import grpc
  6. import message_pb2_grpc as msg_rpc
  7. from ManualOperationWidget import ManualOperationType
  8. from mqtt_async import MqttAsync
  9. import google.protobuf.json_format as jtf
  10. from dijkstra.Map import DijikstraMap, SpaceNode, StreetNode
  11. import uuid
  12. import random
  13. import math
  14. import Count
  15. from sigmoid import sigmoid
  16. class ActType(enum.Enum):
  17. eReady = 0
  18. eRotation = 1
  19. eHorizon = 2
  20. eVertical = 3
  21. eMPC = 4
  22. eClampOpen = 5
  23. eClampClose = 6
  24. class TimeStatu:
  25. def __init__(self, statu=None, timeout=3):
  26. self.statu = statu
  27. self.time = time.time()
  28. self.timeout_ms = timeout
  29. def timeout(self):
  30. tm = time.time()
  31. return tm - self.time > self.timeout_ms or self.statu == None
  32. class Robot(MqttAsync):
  33. def __init__(self, rpc_ipport, name=""):
  34. MqttAsync.__init__(self)
  35. self.timedRobotStatu_ = TimeStatu(message.RobotStatu, 0)
  36. self.timedNavStatu_ = TimeStatu(message.NavStatu, 0)
  37. self.dataTopic_ = {}
  38. self.rpc_ipport_ = rpc_ipport
  39. self.messageArrivedSignal = None
  40. self.currentNavData_ = None
  41. self.navCmdTopic_ = None
  42. self.speedCmdTopic = "monitor_child/speedcmd"
  43. self.currentNavPathNodes_ = None
  44. self.currentNavPath_ = None
  45. self.pathColor_ = [1, 1, 0]
  46. self.robotColor_ = [0.7, 0.2, 0.3] # agv当前颜色
  47. self.name_ = name
  48. self.begId_ = "------"
  49. self.targetId_ = "------"
  50. self.autoTest_ = False
  51. self.l_ = 0.8 # 轮长
  52. self.L_ = 1.3 # 轴距
  53. self.W_ = 2.5 # 宽
  54. self.heat_ = 0 # 心跳
  55. def Color(self):
  56. if self.IsMainModeStatu():
  57. return [0, 0, 0]
  58. return self.robotColor_
  59. def IsMainAgv(self):
  60. if self.timedNavStatu_.timeout() == False:
  61. if self.timedNavStatu_.statu.main_agv == True:
  62. return True
  63. return False
  64. def IsMainModeStatu(self):
  65. if self.IsMainAgv():
  66. if self.timedNavStatu_.timeout() == False:
  67. if self.timedNavStatu_.statu.move_mode == 2:
  68. return True
  69. return False
  70. def SetSubDataTopic(self, match: dict, messageSignal=None):
  71. self.dataTopic_ = match
  72. self.messageArrivedSignal = messageSignal
  73. for item in match.items():
  74. [topic, _] = item
  75. self.subscribe(topic, self.on_message)
  76. def SetCmdTopic(self, topic):
  77. self.navCmdTopic_ = topic
  78. def SetColor(self, pathColor, robotColor):
  79. self.pathColor_ = pathColor
  80. self.robotColor_ = robotColor
  81. def ResetPose(self, agv: message.RobotStatu):
  82. self.timedRobotStatu_ = TimeStatu(agv, 2)
  83. def ResetNavStatu(self, statu: message.NavStatu):
  84. self.timedNavStatu_ = TimeStatu(statu, 2)
  85. def on_message(self, client, userdata, msg):
  86. topic = msg.topic
  87. if self.dataTopic_.get(topic) is not None:
  88. dtype = self.dataTopic_[topic]
  89. if dtype == message.RobotStatu.__name__:
  90. proto = message.RobotStatu()
  91. jtf.Parse(msg.payload.decode(), proto)
  92. self.ResetPose(proto)
  93. if dtype == message.NavStatu.__name__:
  94. self.last_running = self.IsNavigating()
  95. proto = message.NavStatu()
  96. jtf.Parse(msg.payload.decode(), proto)
  97. self.ResetNavStatu(proto)
  98. if self.last_running == True and self.IsNavigating() == False:
  99. self.currentNavPathNodes_ = None
  100. self.currentNavPath_ = None
  101. if self.messageArrivedSignal is not None:
  102. self.messageArrivedSignal()
  103. def MpcSelectTraj(self):
  104. traj = []
  105. if self.timedNavStatu_.timeout() == False:
  106. nav = self.timedNavStatu_.statu
  107. for pose2d in nav.selected_traj.poses:
  108. traj.append([pose2d.x, pose2d.y, pose2d.theta])
  109. return traj
  110. def MpcPredictTraj(self):
  111. traj = []
  112. if self.timedNavStatu_.timeout() == False:
  113. nav = self.timedNavStatu_.statu
  114. for pose2d in nav.predict_traj.poses:
  115. traj.append([pose2d.x, pose2d.y, pose2d.theta])
  116. return traj
  117. def Connected(self):
  118. return self.timedNavStatu_.timeout() == False and self.timedRobotStatu_.timeout() == False
  119. def IsNavigating(self):
  120. return not self.ActionType() == ActType.eReady
  121. '''if self.timedNavStatu_.timeout() == False:
  122. key = self.timedNavStatu_.statu.key
  123. if key == "" or key == None:
  124. return False
  125. return True'''
  126. def GeneratePath(self, begID, endID, task_type="None"):
  127. self.currentNavPathNodes_ = DijikstraMap().GetShortestPath(begID, endID)
  128. if task_type == "DoubleAGV":
  129. print("AdjustPath------------------")
  130. if self.IsMainModeStatu() is False:
  131. print("原始路径:")
  132. for node in self.currentNavPathNodes_:
  133. print(node.id_, node.y_)
  134. self.currentNavPathNodes_ = self.AdjustPath(self.currentNavPathNodes_)
  135. print("修改路径:")
  136. for node in self.currentNavPathNodes_:
  137. print(node.id_, node.y_)
  138. self.currentNavPath_ = DijikstraMap().CreatePath(self.currentNavPathNodes_, 0.5)
  139. if self.currentNavPathNodes_ is not None and self.currentNavPath_ is not None:
  140. self.begId_ = begID
  141. self.targetId_ = endID
  142. return True
  143. return False
  144. def PositionId(self):
  145. if self.timedRobotStatu_.timeout():
  146. return None
  147. x = self.timedRobotStatu_.statu.x
  148. y = self.timedRobotStatu_.statu.y
  149. djks_map = DijikstraMap()
  150. [label, pt] = djks_map.findNeastNode([x, y])
  151. return [label, pt]
  152. '''
  153. 阻塞直到导航完成
  154. '''
  155. def Navigatting(self, begId, targetId, autoDirect, task_type="None"):
  156. print("nav")
  157. self.GeneratePath(begId, targetId, task_type=task_type)
  158. # self.ExecPathNodes(autoDirect)
  159. self.ExecNavtask(autoDirect)
  160. if self.IsMainModeStatu():
  161. Count.TestCount().loadCountAdd()
  162. else:
  163. Count.TestCount().singleCountAdd()
  164. return True
  165. def AutoTestNavClamp(self, begId, targetId):
  166. beg = begId
  167. target = targetId
  168. while self.autoTest_:
  169. if self.TestNavClampOnce(beg, target) == False:
  170. print(" quit auto Test")
  171. break
  172. print("1111")
  173. posInfo = self.PositionId()
  174. if posInfo is not None:
  175. [label, pt] = posInfo
  176. beg = label
  177. print("beg", beg)
  178. node = DijikstraMap().GetVertex(beg)
  179. if node is not None:
  180. if isinstance(node, (SpaceNode)):
  181. target = "O"
  182. if isinstance(node, (StreetNode)):
  183. end_nodes = ["E", "B", "C", "D"]
  184. id = random.randint(0, 1000) % 4
  185. target = end_nodes[id]
  186. print("3333", target)
  187. print(" Next nav clamp cmd,%s to %s" % (beg, target))
  188. def ActionType(self):
  189. if self.timedNavStatu_.timeout() == False:
  190. runningStatu = self.timedNavStatu_.statu
  191. if runningStatu.statu == 0:
  192. return ActType.eReady
  193. if runningStatu.statu == 1:
  194. return ActType.eRotation
  195. if runningStatu.statu == 2:
  196. return ActType.eHorizon
  197. if runningStatu.statu == 3:
  198. return ActType.eVertical
  199. if runningStatu.statu == 4:
  200. return ActType.eMPC
  201. if runningStatu.statu == 5:
  202. return ActType.eClampOpen
  203. if runningStatu.statu == 6:
  204. return ActType.eClampClose
  205. else:
  206. return ActType.eReady
  207. @staticmethod
  208. def generateProtoNode(node):
  209. protoNode = message.PathNode()
  210. protoNode.x = node.x_
  211. protoNode.y = node.y_
  212. protoNode.id = node.id_
  213. return protoNode
  214. def ExecNavtask(self, autoDirect):
  215. cmd = message.NavCmd()
  216. key = str(uuid.uuid4())
  217. cmd.key = key
  218. cmd.action = 0
  219. actions = self.SplitPath(self.currentNavPathNodes_)
  220. for action in actions:
  221. [type, nodes] = action
  222. if type == "input":
  223. [street, space] = nodes
  224. protoSpace = self.generateProtoNode(space)
  225. protoStreet = self.generateProtoNode(street)
  226. act = message.NewAction()
  227. act.type = 1
  228. act.wheelbase = 2.78
  229. act.spaceNode.CopyFrom(protoSpace)
  230. act.streetNode.CopyFrom(protoStreet)
  231. cmd.newActions.add().CopyFrom(act)
  232. if type == "output":
  233. [space, street] = nodes
  234. protoSpace = self.generateProtoNode(space)
  235. protoStreet = self.generateProtoNode(street)
  236. act = message.NewAction()
  237. act.type = 2
  238. act.wheelbase = 2.78
  239. act.spaceNode.CopyFrom(protoSpace)
  240. act.streetNode.CopyFrom(protoStreet)
  241. cmd.newActions.add().CopyFrom(act)
  242. if type == "nav":
  243. action = self.CreateNavPathNodesAction(nodes, autoDirect)
  244. if action is None:
  245. print("Nav cmd is None")
  246. return False
  247. else:
  248. cmd.newActions.add().CopyFrom(action)
  249. print(cmd)
  250. if cmd is None:
  251. print("Nav cmd is None")
  252. return False
  253. channel = grpc.insecure_channel(self.rpc_ipport_)
  254. stub = msg_rpc.NavExcutorStub(channel)
  255. response = stub.Start(cmd)
  256. print("client received: ", response)
  257. if not response.ret == 0:
  258. print("nav failed :%s" % (response.info))
  259. else:
  260. print("nav completed !!!")
  261. return True
  262. def CreateNavPathNodesAction(self, path, autoDirect):
  263. # if path is not None and self.timedRobotStatu_.timeout() == False:
  264. if 1:
  265. for node in path:
  266. if isinstance(node, (SpaceNode)):
  267. print(" nodes must all street node")
  268. return None
  269. statu = self.timedRobotStatu_.statu
  270. # if statu is not None:
  271. if 1:
  272. newAction = message.NewAction()
  273. size = len(path)
  274. for i in range(size):
  275. node = path[i]
  276. pathNode = message.PathNode()
  277. pathNode.x = node.x_
  278. pathNode.y = node.y_
  279. newAction.type = 4
  280. if autoDirect:
  281. newAction.type = 3
  282. newAction.pathNodes.add().CopyFrom(pathNode)
  283. return newAction
  284. else:
  285. print("statu is None")
  286. else:
  287. print("current path is none")
  288. return None
  289. def ExecPathNodes(self, autoDirect):
  290. if self.navCmdTopic_ == None:
  291. print("Robot has not set nav cmd topic")
  292. return False
  293. if not self.ActionType() == ActType.eReady:
  294. print(" robot is navigating ,key:%s" % (self.timedNavStatu_.statu.key))
  295. return False
  296. cmd = message.NavCmd()
  297. key = str(uuid.uuid4())
  298. cmd.key = key
  299. cmd.action = 0
  300. action = self.CreateNavPathNodesAction(self.currentNavPathNodes_, autoDirect)
  301. if action is None:
  302. print("Nav cmd is None")
  303. return False
  304. cmd.newActions.add().CopyFrom(action)
  305. print(cmd)
  306. channel = grpc.insecure_channel(self.rpc_ipport_)
  307. stub = msg_rpc.NavExcutorStub(channel)
  308. response = stub.Start(cmd)
  309. return True
  310. '''
  311. 根据AGV单车的起始位置调整路径
  312. '''
  313. def AdjustPath(self, path):
  314. adjusted_path = copy.deepcopy(path)
  315. y_offset = 1.2
  316. dy = 0
  317. # if self.IsMainAgv() or self.name_ == "AgvMain":
  318. if self.name_ == "AgvMain":
  319. dy = 1
  320. # if not self.IsMainAgv() or self == "AGV2":
  321. if self.name_ == "AGV2":
  322. dy = -1
  323. print("dy:", dy)
  324. for node in adjusted_path:
  325. if isinstance(node, StreetNode):
  326. if dy > 0:
  327. node.y_ += y_offset
  328. elif dy < 0:
  329. node.y_ -= y_offset
  330. else:
  331. pass
  332. return adjusted_path
  333. '''
  334. 拆分路径,生成动作集,input:入库动作,nav:导航动作,output:出库动作
  335. '''
  336. def SplitPath(self, path):
  337. space_count = 0
  338. for i in range(len(path)):
  339. if isinstance(path[i], (SpaceNode)):
  340. space_count += 1
  341. if i == 0 or i == len(path) - 1:
  342. pass
  343. else:
  344. print("Error: space node is not first/last of path")
  345. return None
  346. actions = []
  347. lastNode = None
  348. navIndex = -1
  349. for node in path:
  350. if lastNode == None:
  351. lastNode = node
  352. continue
  353. if isinstance(node, (SpaceNode)): # 当前点是车位点
  354. if isinstance(lastNode, (SpaceNode)): # 上一点为车位点
  355. print("Error: last node and current node is space node ")
  356. lastNode = None
  357. continue
  358. elif isinstance(lastNode, (StreetNode)): # 上一点为马路点,则动作为入库
  359. actions.append(["input", [lastNode, node]])
  360. lastNode = None
  361. continue
  362. if isinstance(node, (StreetNode)):
  363. if isinstance(lastNode, (SpaceNode)): # 上一点为车位点, 出库
  364. actions.append(["output", [lastNode, node]])
  365. elif isinstance(lastNode, (StreetNode)):
  366. if navIndex < 0:
  367. actions.append(["nav", [lastNode]])
  368. navIndex = len(actions) - 1
  369. actions[navIndex][1].append(node)
  370. lastNode = node
  371. return actions
  372. def SwitchMoveMode(self, mode, wheelbase):
  373. if self.IsMainAgv() == False:
  374. print(" this agv is single can not switch mode")
  375. return False
  376. cmd = message.NavCmd()
  377. key = str(uuid.uuid4())
  378. cmd.key = key
  379. cmd.action = 0
  380. action = message.NewAction()
  381. action.type = 8
  382. action.changedMode = mode
  383. if mode == 2:
  384. action.wheelbase = wheelbase
  385. cmd.newActions.add().CopyFrom(action)
  386. channel = grpc.insecure_channel(self.rpc_ipport_)
  387. stub = msg_rpc.NavExcutorStub(channel)
  388. response = stub.Start(cmd)
  389. return False
  390. def IsClampClosed(self):
  391. if self.timedRobotStatu_.timeout() == False:
  392. if self.IsMainModeStatu():
  393. clamp = self.timedRobotStatu_.statu.agvStatu.clamp
  394. clamp_other = self.timedRobotStatu_.statu.agvStatu.clamp_other
  395. return (clamp == 1 and clamp_other == 1)
  396. else:
  397. return self.timedRobotStatu_.statu.agvStatu.clamp == 1
  398. return False
  399. def IsClampRunning(self):
  400. if self.timedRobotStatu_.timeout() == False:
  401. if self.IsMainModeStatu():
  402. clamp = self.timedRobotStatu_.statu.agvStatu.clamp
  403. clamp_other = self.timedRobotStatu_.statu.agvStatu.clamp_other
  404. return (clamp == 0 or clamp_other == 0)
  405. else:
  406. return self.timedRobotStatu_.statu.agvStatu.clamp == 0
  407. return False
  408. def IsClampOpened(self):
  409. if self.timedRobotStatu_.timeout() == False:
  410. if self.IsMainModeStatu():
  411. clamp = self.timedRobotStatu_.statu.agvStatu.clamp
  412. clamp_other = self.timedRobotStatu_.statu.agvStatu.clamp_other
  413. return (clamp == 2 and clamp_other == 2)
  414. else:
  415. return self.timedRobotStatu_.statu.agvStatu.clamp == 2
  416. return False
  417. def ClampClose(self):
  418. if self.IsClampClosed() == True:
  419. print("clamp closed")
  420. return True
  421. cmd = message.NavCmd()
  422. cmd.action = 0
  423. key = str(uuid.uuid4())
  424. cmd.key = (key)
  425. act = message.NewAction()
  426. act.type = 6
  427. cmd.newActions.add().CopyFrom(act)
  428. channel = grpc.insecure_channel(self.rpc_ipport_)
  429. stub = msg_rpc.NavExcutorStub(channel)
  430. response = stub.Start(cmd)
  431. return True
  432. def ClampOpen(self):
  433. if self.IsClampOpened() == True:
  434. print("clamp opended")
  435. return True
  436. cmd = message.NavCmd()
  437. cmd.action = 0
  438. key = str(uuid.uuid4())
  439. cmd.key = (key)
  440. act = message.NewAction()
  441. act.type = 7
  442. cmd.newActions.add().CopyFrom(act)
  443. channel = grpc.insecure_channel(self.rpc_ipport_)
  444. stub = msg_rpc.NavExcutorStub(channel)
  445. response = stub.Start(cmd)
  446. return True
  447. def CancelNavTask(self):
  448. cmd = message.NavCmd()
  449. cmd.action = 3
  450. channel = grpc.insecure_channel(self.rpc_ipport_)
  451. stub = msg_rpc.NavExcutorStub(channel)
  452. response = stub.Cancel(cmd)
  453. print("client received: ", response)
  454. print(" Cancel task completed!!!")
  455. return True
  456. def ManualTask(self, current_operation):
  457. cmd = message.ToAgvCmd()
  458. self.heat_ += 1
  459. self.heat_ %= 255
  460. cmd.H = self.heat_
  461. if self.IsMainModeStatu():
  462. cmd.M = 2
  463. else:
  464. cmd.M = 1
  465. if current_operation == ManualOperationType.eCounterclockwiseRotate:
  466. cmd.T = 1
  467. cmd.V = 0
  468. cmd.W = 2.0/180*math.pi
  469. if current_operation == ManualOperationType.eClockwiseRotate:
  470. cmd.T = 1
  471. cmd.V = 0
  472. cmd.W = -2.0 / 180 * math.pi
  473. if current_operation == ManualOperationType.eForwardMove:
  474. cmd.T = 3
  475. cmd.V = 0.5
  476. cmd.W = 0
  477. if current_operation == ManualOperationType.eBackwardMove:
  478. cmd.T = 3
  479. cmd.V = -0.5
  480. cmd.W = 0
  481. if current_operation == ManualOperationType.eLeftMove:
  482. cmd.T = 2
  483. cmd.V = 0.5
  484. cmd.W = 0
  485. if current_operation == ManualOperationType.eRightMove:
  486. cmd.T = 2
  487. cmd.V = -0.5
  488. cmd.W = 0
  489. cmd.L = self.L_
  490. cmd.end = 1
  491. self.publish(self.speedCmdTopic, jtf.MessageToJson(cmd))
  492. # cmd_0 = message.ManualCmd()
  493. # cmd_0.key = str(uuid.uuid4())
  494. # if current_operation == ManualOperationType.eCounterclockwiseRotate:
  495. # cmd_0.operation_type = 1
  496. # cmd_0.velocity = 1
  497. # if current_operation == ManualOperationType.eClockwiseRotate:
  498. # cmd_0.operation_type = 1
  499. # cmd_0.velocity = -1
  500. # if current_operation == ManualOperationType.eForwardMove:
  501. # cmd_0.operation_type = 2
  502. # cmd_0.velocity = 1
  503. # if current_operation == ManualOperationType.eBackwardMove:
  504. # cmd_0.operation_type = 2
  505. # cmd_0.velocity = -1
  506. # if current_operation == ManualOperationType.eLeftMove:
  507. # cmd_0.operation_type = 3
  508. # cmd_0.velocity = 1
  509. # if current_operation == ManualOperationType.eRightMove:
  510. # cmd_0.operation_type = 3
  511. # cmd_0.velocity = -1
  512. #
  513. # channel = grpc.insecure_channel(self.rpc_ipport_)
  514. # stub = msg_rpc.NavExcutorStub(channel)
  515. # response = stub.ManualOperation(cmd_0)
  516. # print("client received: ", response)
  517. print(cmd)
  518. print("ManualOperation {op_type} task completed!!!".format(op_type=current_operation))
  519. return True