RobotData.py 21 KB

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