decisiondemo.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import proto.gpsimu_pb2 as gpsimu_pb2
  2. #import gpsimu_pb2
  3. import proto.mapdata_pb2 as mapdata_pb2
  4. import proto.decition_pb2 as decition_pb2
  5. from proto import objectarray_pb2 as objectarray_pb2
  6. import math
  7. from typing import List
  8. from datetime import datetime, timedelta
  9. import time
  10. class Point2D:
  11. def __init__(self, x, y,hdg):
  12. self.mx = x
  13. self.my = y
  14. self.mhdg = hdg
  15. while self.mhdg < 0:
  16. self.mhdg = self.mhdg + 2.0* math.pi
  17. while self.mhdg >= 2.0*math.pi:
  18. self.mhdg = self.mhdg - 2.0* math.pi
  19. def __str__(self):
  20. return f"Point2D({self.mx}, {self.my})"
  21. class DecisionDemo:
  22. def __init__(self):
  23. # 初始化代码...
  24. self.mendacc = -0.7 #抵达终点时的舰速度为-0.7
  25. self.mmaxwheel = 430 #最大方向盘角度
  26. self.mdefaultacc = 1.0 #加速时的acc
  27. self.mspeed = 10.0 #运行速度10km/h
  28. self.mstopdistoobs = 6.0 #在距离障碍物多远停住
  29. self.mstopdisacc = -1.0 #有障碍物时的舰速度
  30. self.mvehwidth = 2.3
  31. pass
  32. def CalcDecision(self,tracemap : mapdata_pb2.tracemap, msg_gpsimu : gpsimu_pb2.gpsimu,xobjarray : objectarray_pb2.objectarray):
  33. # x,y = self.GaussProj(gpsimu_pb2.lon,gpsimu_pb2.lat)
  34. # print(" in calc: map size: ",len(tracemap.point))
  35. nearindex = self.FindNearIndex(tracemap,msg_gpsimu)
  36. # print("near index: ",nearindex)
  37. # for p in xobjarray.obj :
  38. # print(f"x: {p.position.x} y: {p.position.y} ")
  39. if nearindex < 0 :
  40. print(" not found near point, return")
  41. return
  42. localpoints,distoend = self.CalcLocalPath(nearindex,tracemap,msg_gpsimu)
  43. # print(f"disttoend: {distoend}")
  44. realspeed = 3.6 * math.sqrt(math.pow(msg_gpsimu.vn,2) + math.pow(msg_gpsimu.ve,2))
  45. acc,wheel,speed = self.CalcCmd(localpoints,realspeed,xobjarray)
  46. #calc end acc, stop to end point
  47. endacc = 0.0
  48. if distoend > 0.1:
  49. if distoend < math.pow(realspeed/3.6,2)/(2*math.fabs(self.mendacc)) :
  50. endacc = math.pow(realspeed/3.6,2)/(2*distoend) *(-1.0)
  51. print("endacc: ",endacc)
  52. else :
  53. endacc = self.mendacc
  54. # print("endacc: ",endacc)
  55. if endacc<-1e-9:
  56. acc = endacc
  57. if acc < -5.0:
  58. acc = -5.0
  59. xdecisiion = decition_pb2.decition()
  60. xdecisiion.wheelAngle = wheel
  61. xdecisiion.accelerator = acc
  62. xdecisiion.brake = 0
  63. xdecisiion.speed = speed
  64. print("acc = : ",acc)
  65. if acc < 0:
  66. xdecisiion.brake = acc
  67. xdecisiion.torque = 0
  68. else:
  69. xdecisiion.brake = 0
  70. fVehWeight = 1800
  71. # fg = 9.8
  72. fRollForce = 50
  73. fRatio = 2.5
  74. fNeed = fRollForce + fVehWeight*acc
  75. xdecisiion.torque = fNeed/fRatio
  76. return xdecisiion
  77. def CalcCmd(self,localpoints : List[Point2D],realspeed,xobjarray : objectarray_pb2.objectarray):
  78. desiredspeed = self.mspeed
  79. defaultacc = self.mdefaultacc
  80. pd = realspeed * 0.3
  81. if pd < 4.0 :
  82. pd = 4.0
  83. sumdis = 0
  84. i = 1
  85. size = len(localpoints)
  86. ppindex = 0
  87. while i < size:
  88. sumdis = sumdis + math.sqrt(math.pow(localpoints[i].mx - localpoints[i-1].mx,2)
  89. + math.pow(localpoints[i].my - localpoints[i-1].my,2))
  90. ppindex = i
  91. if sumdis >= pd :
  92. ppindex = i
  93. break
  94. i = i+1
  95. acc = -0.5
  96. wheel = 0.0
  97. if ppindex < 3:
  98. acc = 0.0
  99. wheel = 0.0
  100. return acc,wheel,0
  101. if desiredspeed > 0.1:
  102. if realspeed < desiredspeed :
  103. if realspeed < desiredspeed*0.9:
  104. acc = defaultacc
  105. else:
  106. acc = defaultacc *(desiredspeed - realspeed) * (1/0.1)/desiredspeed
  107. else:
  108. if realspeed > desiredspeed*1.1:
  109. if realspeed > desiredspeed * 2.0:
  110. acc = defaultacc * (-1.0)
  111. else:
  112. acc = defaultacc * (desiredspeed - realspeed)/desiredspeed
  113. else:
  114. acc = 0.0
  115. obsdis = 0
  116. bhaveobs = False
  117. i = 0
  118. gridsize = 0.2
  119. gridcount = int((self.mvehwidth/2.0)/gridsize)*2
  120. xwid = gridcount * gridsize
  121. if xwid < self.mvehwidth:
  122. gridcount = gridcount +2
  123. while i< size:
  124. if i > 0:
  125. obsdis = obsdis + math.sqrt(math.pow(localpoints[i].mx - localpoints[i-1].mx,2)
  126. +math.pow(localpoints[i].my - localpoints[i-1].my,2))
  127. nobjsize = len(xobjarray.obj)
  128. j = 0
  129. bprob = False #查看有没有可能
  130. for pobj in xobjarray.obj:
  131. dis = math.sqrt(math.pow(localpoints[i].mx - pobj.position.x,2)+ math.pow(localpoints[i].my - pobj.position.y,2))
  132. # print("dis: ",dis)
  133. # print("dimen: ",pobj.dimensions.x)
  134. if (dis < (self.mvehwidth/2.0 + pobj.dimensions.x)) or (dis < (self.mvehwidth/2.0 + pobj.dimensions.y)):
  135. bprob = True
  136. if (bprob == True):
  137. break
  138. if bprob == False:
  139. i = i+1
  140. continue
  141. j =0
  142. while j <= gridcount:
  143. off = (j - gridcount/2)*gridsize
  144. xpos = localpoints[i].mx + off * math.cos(localpoints[i].mhdg + math.pi/2.0)
  145. ypos = localpoints[i].my + off * math.sin(localpoints[i].mhdg + math.pi/2.0)
  146. for pobj in xobjarray.obj:
  147. bres = self.is_point_in_rotated_rectangle(xpos,ypos,pobj.position.x,pobj.position.y,pobj.tyaw,
  148. pobj.dimensions.x,pobj.dimensions.y)
  149. if bres == True:
  150. bhaveobs = True
  151. break
  152. if bhaveobs == True:
  153. break
  154. j = j+1
  155. if bhaveobs == True:
  156. break
  157. i = i+1
  158. if bhaveobs == True :
  159. print("obs dis: ",obsdis)
  160. vel = realspeed/3.6
  161. srange = vel*vel/(2*(math.fabs(self.mstopdisacc)/2.0)) + self.mstopdistoobs
  162. if obsdis <= srange:
  163. if obsdis < (self.mstopdistoobs + 0.1):
  164. stopacc = -3.0
  165. if acc > stopacc:
  166. acc = stopacc
  167. else :
  168. stopacc = -1.0*vel * vel/(2.0*(obsdis - self.mstopdistoobs))
  169. if acc > stopacc:
  170. acc = stopacc
  171. if obsdis < self.mstopdistoobs * 1.1:
  172. if acc >= 0:
  173. acc = self.mstopdisacc
  174. # print("ppindex : ",ppindex)
  175. denominator = 2 * localpoints[ppindex].mx *(-1);
  176. numerator = math.pow(localpoints[ppindex].mx,2) + pow(localpoints[ppindex].my,2)
  177. fRadius = 1e9
  178. if math.fabs(denominator)>0:
  179. fRadius = numerator/denominator
  180. else:
  181. fRadius = 1e9
  182. if fRadius == 0:
  183. wheel = 0
  184. kappa = 1.0/fRadius
  185. wheel_base = 2.9
  186. wheelratio = 13.6
  187. wheel = (1.0)*kappa * wheel_base * wheelratio * 180.0/math.pi
  188. if wheel>self.mmaxwheel:
  189. wheel = self.mmaxwheel
  190. if wheel<(self.mmaxwheel * (-1.0)):
  191. wheel = self.mmaxwheel * (-1.0)
  192. return acc,wheel,self.mspeed
  193. def FindNearIndex(self,tracemap : mapdata_pb2.tracemap,xgpsimu : gpsimu_pb2.gpsimu) :
  194. x,y = self.GaussProj(xgpsimu.lon,xgpsimu.lat)
  195. nearindex = -1
  196. neardis = 100000
  197. index = 0
  198. for p in tracemap.point:
  199. dis = math.sqrt(math.pow(x - p.gps_x,2) + math.pow(y - p.gps_y,2))
  200. headingdiff = xgpsimu.heading - p.ins_heading_angle
  201. while headingdiff < -180:
  202. headingdiff = headingdiff + 360
  203. while headingdiff >= 180:
  204. headingdiff = headingdiff - 360
  205. if math.fabs(headingdiff) < 80 :
  206. if dis < neardis :
  207. neardis = dis
  208. nearindex = index
  209. index = index + 1
  210. return nearindex
  211. def CalcLocalPath(self,index,xtracemap : mapdata_pb2.tracemap,xgpsimu : gpsimu_pb2.gpsimu):
  212. x0,y0 = self.GaussProj(xgpsimu.lon,xgpsimu.lat)
  213. localpoints = []
  214. i = index
  215. npoint = 0
  216. nmaxpoint = 600
  217. length = len(xtracemap.point)
  218. distoend = 0;
  219. while i< length :
  220. xraw = xtracemap.point[i].gps_x - x0
  221. yraw = xtracemap.point[i].gps_y - y0
  222. # print(f"i: {i-index} xraw:{xraw} yraw:{yraw} ")
  223. theta = (90 - xgpsimu.heading) * math.pi /180.0
  224. thetaraw = theta
  225. pointhead = (90 - xtracemap.point[i].ins_heading_angle ) * math.pi/180.0;
  226. theta = theta * (-1)
  227. theta = theta + math.pi/2.0
  228. x = xraw * math.cos(theta) - yraw * math.sin(theta)
  229. y = xraw * math.sin(theta) + yraw * math.cos(theta)
  230. # print(f"i: {i-index} x:{x} y:{y} hdg:{pointhead - thetaraw + math.pi/2.0}")
  231. localpoints.append(Point2D(x,y, pointhead - thetaraw + math.pi/2.0))
  232. if i>index :
  233. distoend = distoend + math.sqrt(math.pow(xtracemap.point[i].gps_x - xtracemap.point[i-1].gps_x,2)
  234. + math.pow(xtracemap.point[i].gps_y - xtracemap.point[i-1].gps_y,2))
  235. if npoint >= nmaxpoint:
  236. break
  237. i = i+1
  238. npoint = npoint + 1
  239. while i < length :
  240. if i>index :
  241. distoend = distoend + math.sqrt(math.pow(xtracemap.point[i].gps_x - xtracemap.point[i-1].gps_x,2)
  242. + math.pow(xtracemap.point[i].gps_y - xtracemap.point[i-1].gps_y,2))
  243. i = i+1
  244. if distoend > 300:
  245. break
  246. return localpoints,distoend
  247. def is_point_in_rotated_rectangle(self,x, y, x1, y1, yaw, l, w):
  248. # 将长方形的左下角坐标转换到原点
  249. x_rel = x - x1
  250. y_rel = y - y1
  251. # 计算旋转矩阵(逆时针旋转)
  252. # | cos(yaw) -sin(yaw) |
  253. # | sin(yaw) cos(yaw) |
  254. cos_yaw = math.cos(yaw)
  255. sin_yaw = math.sin(yaw)
  256. # 应用旋转矩阵到相对坐标
  257. x_rotated = x_rel * cos_yaw + y_rel * sin_yaw
  258. y_rotated = -x_rel * sin_yaw + y_rel * cos_yaw
  259. # 判断点是否在旋转后的长方形内
  260. # 长方形的边界在旋转后的坐标系中是 [-l/2, l/2] x [-w/2, w/2]
  261. if -l/2 <= x_rotated <= l/2 and -w/2 <= y_rotated <= w/2:
  262. return True
  263. else:
  264. return False
  265. def GaussProj(self,lon,lat):
  266. iPI = 0.0174532925199433
  267. ZoneWide = 6
  268. a = 6378245.0
  269. f = 1.0 / 298.3
  270. ProjNo = int(lon / ZoneWide)
  271. longitude0 = ProjNo * ZoneWide + ZoneWide / 2
  272. longitude0 = longitude0 * iPI
  273. latitude0 = 0
  274. longitude1 = lon * iPI #经度转换为弧度
  275. latitude1 = lat * iPI #//纬度转换为弧度
  276. e2 = 2 * f - f * f
  277. ee = e2 * (1.0 - e2)
  278. NN = a / math.sqrt(1.0 - e2 * math.sin(latitude1)*math.sin(latitude1))
  279. T = math.tan(latitude1)*math.tan(latitude1)
  280. C = ee * math.cos(latitude1)*math.cos(latitude1)
  281. A = (longitude1 - longitude0)*math.cos(latitude1)
  282. M = a * ((1 - e2 / 4 - 3 * e2*e2 / 64 - 5 * e2*e2*e2 / 256)*latitude1 - (3 * e2 / 8 + 3 * e2*e2 / 32 + 45 * e2*e2*e2 / 1024)*math.sin(2 * latitude1)+ (15 * e2*e2 / 256 + 45 * e2*e2*e2 / 1024)*math.sin(4 * latitude1) - (35 * e2*e2*e2 / 3072)*math.sin(6 * latitude1))
  283. xval = NN * (A + (1 - T + C)*A*A*A / 6 + (5 - 18 * T + T * T + 72 * C - 58 * ee)*A*A*A*A*A / 120)
  284. yval = M + NN * math.tan(latitude1)*(A*A / 2 + (5 - T + 9 * C + 4 * C*C)*A*A*A*A / 24 + (61 - 58 * T + T * T + 600 * C - 330 * ee)*A*A*A*A*A*A / 720)
  285. X0 = 1000000 * (ProjNo + 1) + 500000
  286. Y0 = 0
  287. xval = xval + X0; yval = yval + Y0;
  288. X = xval
  289. Y = yval
  290. return X,Y
  291. def GaussProjInvCal(self,X,Y):
  292. iPI = 0.0174532925199433 #3.1415926535898/180.0;
  293. a = 6378245.0
  294. f = 1.0 / 298.3 # //54年北京坐标系参数
  295. #////a=6378140.0; f=1/298.257; //80年西安坐标系参数
  296. ZoneWide = 6 # ////6度带宽
  297. ProjNo = int(X / 1000000) # //查找带号
  298. longitude0 = (ProjNo - 1) * ZoneWide + ZoneWide / 2
  299. longitude0 = longitude0 * iPI # //中央经线
  300. X0 = ProjNo * 1000000 + 500000
  301. Y0 = 0
  302. xval = X - X0; yval = Y - Y0 #//带内大地坐标
  303. e2 = 2 * f - f * f
  304. e1 = (1.0 - math.sqrt(1 - e2)) / (1.0 + math.sqrt(1 - e2))
  305. ee = e2 / (1 - e2)
  306. M = yval
  307. u = M / (a*(1 - e2 / 4 - 3 * e2*e2 / 64 - 5 * e2*e2*e2 / 256))
  308. fai = u + (3 * e1 / 2 - 27 * e1*e1*e1 / 32)*math.sin(2 * u) + (21 * e1*e1 / 16 - 55 * e1*e1*e1*e1 / 32)*math.sin(4 * u)+ (151 * e1*e1*e1 / 96)*math.sin(6 * u) + (1097 * e1*e1*e1*e1 / 512)*math.sin(8 * u)
  309. C = ee * math.cos(fai)*math.cos(fai)
  310. T = math.tan(fai)*math.tan(fai)
  311. NN = a / math.sqrt(1.0 - e2 * math.sin(fai)*math.sin(fai))
  312. R = a * (1 - e2) / math.sqrt((1 - e2 * math.sin(fai)*math.sin(fai))*(1 - e2 * math.sin(fai)*math.sin(fai))*(1 - e2 * math.sin(fai)*math.sin(fai)))
  313. D = xval / NN
  314. #//计算经度(Longitude) 纬度(Latitude)
  315. longitude1 = longitude0 + (D - (1 + 2 * T + C)*D*D*D / 6 + (5 - 2 * C + 28 * T - 3 * C*C + 8 * ee + 24 * T*T)*D*D*D*D*D / 120) / math.cos(fai)
  316. latitude1 = fai - (NN*math.tan(fai) / R)*(D*D / 2 - (5 + 3 * T + 10 * C - 4 * C*C - 9 * ee)*D*D*D*D / 24 + (61 + 90 * T + 298 * C + 45 * T*T - 256 * ee - 3 * C*C)*D*D*D*D*D*D / 720)
  317. #//转换为度 DD
  318. longitude = longitude1 / iPI
  319. latitude = latitude1 / iPI
  320. return longitude,latitude