BlDecisionControler.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. using ProjectBase.Data.BaseDAL;
  2. using ProjectBase.Data.Logs;
  3. using ProjectBase.Data.Redis;
  4. using ProjectBase.Util;
  5. using SIASUN.Autopilot.GNSS;
  6. using SIASUN.Autopilot.Model;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace SIASUN.Autopilot.BLL
  12. {
  13. public class BlDecisionControler
  14. {
  15. /// <summary>
  16. /// 参考路径起始点
  17. /// </summary>
  18. private WGS84Points startPointRef = new WGS84Points();
  19. /// <summary>
  20. /// 当前路径起始点
  21. /// </summary>
  22. private WGS84Points startPointCur = new WGS84Points();
  23. /// <summary>
  24. /// 当前点
  25. /// </summary>
  26. private WGS84Points pointCur = new WGS84Points();
  27. // 当前速度
  28. private double SpeedCur;
  29. /// <summary>
  30. /// 地球的半径
  31. /// </summary>
  32. private const double EARTH_RADIUS = 6378.137;
  33. RedisHelper redis = new RedisHelper(0);
  34. List<MoLocationRuleInfo> locationList = new List<MoLocationRuleInfo>();
  35. private string PointsToOrigin = "pointstoorigin";
  36. /// <summary>
  37. /// 角度误差
  38. /// </summary>
  39. private const double angleError = 0.102;
  40. /// <summary>
  41. /// 速度误差
  42. /// </summary>
  43. private const double speedError = 0.103;
  44. /// <summary>
  45. /// 参考距离--用于动作指令判断
  46. /// </summary>
  47. private double distanceRefAction = 0;
  48. /// <summary>
  49. /// 参考角度--用于动作指令判断
  50. /// </summary>
  51. private double angleRefAction = 0;
  52. /// <summary>
  53. /// 参考速度--用于动作指令判断
  54. /// </summary>
  55. private double speedRefAction = 0;
  56. /// <summary>
  57. /// 执行到第几个动作指令
  58. /// </summary>
  59. private int count = 1;
  60. private bool bLock = true;
  61. //public event EventStartPointHandler StartPointHandler;
  62. public event EventHandler<StartPointEventArgs> StartPointHandler;
  63. public BlDecisionControler()
  64. {
  65. InitPlanRoute();
  66. BlGNSSPerception.Instance.GNSSHandler += Instance_GNSSHandler;
  67. }
  68. private void Instance_GNSSHandler(object sender, GNSSInfoEventArgs e)
  69. {
  70. LogHelper.log.Debug("控制指令算法执行");
  71. string msg = "";
  72. string start = redis.GetString(SysEnvironment.Start);
  73. if (start.Equals("1"))
  74. {
  75. if (Math.Abs(((double)e.Nmea.gpgga.Latitude - startPointRef.y)) > 0.0000001)// 验证起始点是否在10cm范围内
  76. {
  77. LogHelper.log.Debug("通过纬度验证起始点不在范围内");
  78. return;
  79. }
  80. if (Math.Abs(((double)e.Nmea.gpgga.Longitude - startPointRef.x)) > 0.0000001)
  81. {
  82. LogHelper.log.Debug("通过经度验证起始点不在范围内");
  83. return;
  84. }
  85. msg = "车辆运行到起始点。请开始测试!";
  86. LogHelper.log.Debug(msg);
  87. StartPointEventArgs message = new StartPointEventArgs(msg);
  88. if (StartPointHandler != null)
  89. {
  90. StartPointHandler(sender,message);
  91. }
  92. startPointCur.x = (double)e.Nmea.gpgga.Longitude;
  93. startPointCur.y = (double)e.Nmea.gpgga.Latitude;
  94. redis.SetString(SysEnvironment.Start, "0");
  95. }
  96. pointCur.x = (double)e.Nmea.gpgga.Longitude;
  97. pointCur.y = (double)e.Nmea.gpgga.Latitude;
  98. SpeedCur = (double)e.Nmea.gprmc.Speed;
  99. UpdateDirective();
  100. if (bLock)
  101. {
  102. bLock = false;
  103. Task task = new Task(() =>
  104. {
  105. ExcutePid();
  106. bLock = true;
  107. });
  108. task.Start();
  109. }
  110. }
  111. /// <summary>
  112. /// 获取规划路径的各个点到起始点的距离
  113. /// </summary>
  114. private double GetDistance(WGS84Points startPoint, WGS84Points endPoint)
  115. {
  116. double lat = startPoint.y - endPoint.y;
  117. double lon = startPoint.x - endPoint.x;
  118. double dis = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(lat / 2), 2) +
  119. Math.Cos(startPoint.y) * Math.Cos(endPoint.y) * Math.Pow(Math.Sin(lon / 2), 2)));
  120. dis = dis * EARTH_RADIUS;
  121. dis = Math.Round(dis * 1e4) / 1e4;
  122. return dis;
  123. }
  124. /// <summary>
  125. /// 求出任何一点到起始点的角度的tan值
  126. /// </summary>
  127. /// <param name="startPoint"></param>
  128. /// <param name="endPoint"></param>
  129. /// <returns></returns>
  130. private double GetTanAngle(WGS84Points startPoint, WGS84Points endPoint)
  131. {
  132. WGS84Points endPointX = new WGS84Points();
  133. endPointX.x = endPoint.x;
  134. endPointX.y = startPoint.y;
  135. double distanceX = GetDistance(startPoint, endPointX);
  136. WGS84Points endPointY = new WGS84Points();
  137. endPointY.x = startPoint.x;
  138. endPointY.y = endPoint.y;
  139. double distanceY = GetDistance(startPoint, endPointY);
  140. return distanceY / distanceX;
  141. }
  142. /// <summary>
  143. /// 计算点到线段的距离
  144. /// </summary>
  145. /// <param name="point">点的坐标</param>
  146. /// <param name="startPoint">线段起始点坐标</param>
  147. /// <param name="endPoint">线段终止点坐标</param>
  148. /// <returns></returns>
  149. private double GetPointLineDistance(WGS84Points point,WGS84Points startPoint, WGS84Points endPoint)
  150. {
  151. double a = GetDistance(startPoint,endPoint);
  152. double b = GetDistance(endPoint,point);
  153. double c = GetDistance(startPoint,point);
  154. if (b*b >= c*c + a*a)
  155. {
  156. return c;
  157. }
  158. if (c*c >= b*b + a*a)
  159. {
  160. return b;
  161. }
  162. double p = (a + b + c) / 2; //周长的一半
  163. double s = Math.Sqrt(p * (p - a) * (p - b) * (p - c)); //海伦公式求面积
  164. double dis = 2.0 * s / a;
  165. dis = Math.Round(dis * 1e4) / 1e4;
  166. return dis;
  167. }
  168. /// <summary>
  169. /// 计算各点到原点的距离和角度
  170. /// </summary>
  171. public void InitPlanRoute()
  172. {
  173. try
  174. {
  175. string condition = string.Format("rule_name = '{0}'", SysEnvironment.CurrentRuleName);
  176. locationList = BLLFactory<BlLocationRuleInfo>.Instance.Find(condition);
  177. startPointRef.x = locationList[0].LocationLon;
  178. startPointRef.y = locationList[0].LocationLat;
  179. startPointRef.z = locationList[0].LocationHeight;
  180. for (int i = 1; i < locationList.Count; i++)
  181. {
  182. WGS84Points endPoint = new WGS84Points();
  183. endPoint.x = locationList[i].LocationLon;
  184. endPoint.y = locationList[i].LocationLat;
  185. PointsToOrigin origin = new PointsToOrigin();
  186. origin.Height = endPoint.z = locationList[i].LocationHeight;
  187. origin.distance = GetDistance(startPointRef, endPoint);
  188. origin.TanAngle = GetTanAngle(startPointRef, endPoint);
  189. origin.Speed = locationList[i].LocationSpeed;
  190. redis.SetHash(PointsToOrigin, i.ToString(), origin);
  191. }
  192. PointsToOrigin Reference = new PointsToOrigin();
  193. Reference = redis.GetHash<PointsToOrigin>(PointsToOrigin, count.ToString());
  194. distanceRefAction = Reference.distance;
  195. angleRefAction = Reference.TanAngle;
  196. speedRefAction = Reference.Speed;
  197. }
  198. catch (Exception ex)
  199. {
  200. LogHelper.log.Error("计算规划的路径距离原点距离和Tan角度出现错误", ex);
  201. }
  202. }
  203. private int i = 1;
  204. /// <summary>
  205. /// 执行加减速和方向控制的PID算法
  206. /// </summary>
  207. private void ExcutePid()
  208. {
  209. double distanceCur = GetDistance(startPointCur, pointCur);
  210. double tan = GetTanAngle(startPointCur, pointCur);
  211. PointsToOrigin Reference = new PointsToOrigin();
  212. int A = 0, B = 0;
  213. do
  214. {
  215. Reference = redis.GetHash<PointsToOrigin>(PointsToOrigin, i.ToString());
  216. B = i;
  217. A = i - 1;
  218. i++;
  219. }
  220. while (Reference.distance >= distanceCur && Math.Abs(Reference.TanAngle - tan) <= angleError);
  221. WGS84Points pointA = new WGS84Points();
  222. pointA.x = locationList[A].LocationLon;
  223. pointA.y = locationList[A].LocationLat;
  224. WGS84Points pointB = new WGS84Points();
  225. pointB.x = locationList[B].LocationLon;
  226. pointB.y = locationList[B].LocationLat;
  227. double accFactor = 0, befAccFactor = 0;
  228. PidAlgorithm accPid = new PidAlgorithm(1, 1, 1); // TODO传入比例系数
  229. double tempSpeed = 0, speedLast = 0, curSpeedError = 0, befSpeedError1 = 0, befSpeedError2 = 0;
  230. double angFactor = 0, befAangFactor = 0;
  231. PidAlgorithm angPid = new PidAlgorithm(1, 1, 1); // TODO传入比例系数
  232. double tempAng = 0, curAngError = 0, befAngError1 = 0, befAngError2 = 0;
  233. do
  234. {
  235. double curSpeed = BlCanBusPerception.Instance.GetRealSpeed; // 调用Can总线接口,获取实时速度
  236. double acceleration = (curSpeed - speedLast) / timeSpan / PreNumbers;
  237. double preSpeed = PreSpeed(curSpeed, acceleration);
  238. curSpeedError = preSpeed - Reference.Speed;
  239. speedLast = curSpeed;
  240. double factorx = PrePointFactorX(Math.Atan(tan), angFactor, curSpeed, acceleration, startPointCur, pointCur);
  241. double factory = PrePointFactorY(Math.Atan(tan), angFactor, curSpeed, acceleration, startPointCur, pointCur);
  242. pointCur.x += pointCur.x * factorx;
  243. pointCur.y += pointCur.y * factory;
  244. curAngError = GetPointLineDistance(pointCur, pointA, pointB);
  245. accFactor = accPid.Pid(befAccFactor, curSpeedError, befSpeedError1, befSpeedError2);
  246. // 调用加速接口
  247. //BeckhoffDrive.Accelerator((float)accFactor);
  248. string condition = string.Format("当前油门系数值{0}", accFactor);
  249. LogHelper.log.Debug(condition);
  250. befAccFactor = accFactor;
  251. befSpeedError1 = curSpeedError;
  252. befSpeedError2 = tempSpeed;
  253. tempSpeed = befSpeedError1;
  254. angFactor = angPid.Pid(befAangFactor, curAngError, befAngError1, befAngError2);
  255. // 调用转盘方向角,基于当前角度调整
  256. //BeckhoffDrive.SteerAngCt((float)angFactor);
  257. condition = string.Format("当前转盘方向角{0}", angFactor);
  258. LogHelper.log.Debug(condition);
  259. befAangFactor = angFactor;
  260. befAngError1 = curAngError;
  261. befAngError2 = tempAng;
  262. tempAng = befAngError1;
  263. Thread.Sleep(50);
  264. }
  265. while ((accFactor != 0) && (angFactor != 0));
  266. }
  267. /// <summary>
  268. /// 更新指令集执行结果
  269. /// </summary>
  270. private void UpdateDirective()
  271. {
  272. try
  273. {
  274. double distance = GetDistance(startPointCur, pointCur);
  275. double angle = GetTanAngle(startPointCur, pointCur);
  276. if (distanceRefAction <= distance && Math.Abs(angleRefAction - angle) <= angleError)
  277. {
  278. string speed = "00";
  279. MoActionDirective mo = BLLFactory<BlActionDirective>.Instance.FindByID(new object[] { SysEnvironment.CurrentRuleName, count });
  280. //更新数据库
  281. if (Math.Abs(Convert.ToDouble(speed) - speedRefAction) <= speedError)
  282. {
  283. mo.DirectiveResult = 1;
  284. }
  285. else
  286. {
  287. mo.DirectiveResult = 0;
  288. }
  289. BLLFactory<BlActionDirective>.Instance.Update(mo, new object[] { SysEnvironment.CurrentRuleName, count });
  290. //下一个指令信息
  291. count++;
  292. PointsToOrigin Reference = new PointsToOrigin();
  293. Reference = redis.GetHash<PointsToOrigin>(PointsToOrigin, count.ToString());
  294. distanceRefAction += Reference.distance;
  295. angleRefAction = Reference.TanAngle;
  296. speedRefAction = Reference.Speed;
  297. }
  298. }
  299. catch (Exception ex)
  300. {
  301. LogHelper.log.Error(string.Format("更新动作指令执行结果失败:{0}", ex.ToString()));
  302. }
  303. }
  304. #region 预测模型
  305. public double timeSpan = 0.05; // 预测时间间隔
  306. public double longf = 2.0; // 前轮到重心的距离
  307. public double longr = 2.0; // 后轮到重心的距离
  308. public int PreNumbers = 10;
  309. /// <summary>
  310. /// 预测模型中的速度值
  311. /// </summary>
  312. /// <param name="speedCur"></param>
  313. /// <param name="acceleration"></param>
  314. /// <returns></returns>
  315. private double PreSpeed(double speedCur, double acceleration)
  316. {
  317. double speedPre = speedCur;
  318. for (int i = 0; i < PreNumbers; i++)
  319. {
  320. speedPre += acceleration * timeSpan;
  321. }
  322. return speedPre;
  323. }
  324. /// <summary>
  325. /// 预测模型中的前一个点的角度值
  326. /// </summary>
  327. /// <param name="angleRef"></param>
  328. /// <param name="anglePid"></param>
  329. /// <param name="speedCur"></param>
  330. /// <param name="acceleration"></param>
  331. /// <returns></returns>
  332. private double PreAngle(double angleCur, double anglePid, double speedCur, double acceleration)
  333. {
  334. double b = Math.Atan(longr / (longf + longr) * Math.Tan(anglePid));
  335. double anglePre = angleCur;
  336. double speedPre = speedCur;
  337. for (int i = 0; i < PreNumbers - 1; i++)
  338. {
  339. speedPre += acceleration * timeSpan;
  340. anglePre += speedPre / longr * Math.Sin(b) * timeSpan;
  341. }
  342. return anglePre;
  343. }
  344. /// <summary>
  345. /// 预测模型中X坐标比例系数,相对于当前坐标值的比例系数
  346. /// </summary>
  347. /// <param name="angleCur"></param>
  348. /// <param name="anglePid"></param>
  349. /// <param name="preAngle"></param>
  350. /// <param name="speedCur"></param>
  351. /// <param name="acceleration"></param>
  352. /// <param name="startPoint"></param>
  353. /// <param name="endPoint"></param>
  354. /// <returns></returns>
  355. private double PrePointFactorX(double angleCur, double anglePid, double speedCur,
  356. double acceleration, WGS84Points startPoint, WGS84Points endPoint)
  357. {
  358. double b = Math.Atan(longr / (longf + longr) * Math.Tan(anglePid));
  359. double speedPre = speedCur;
  360. double anglePre = angleCur;
  361. double tempx = 0;
  362. for (int i = 0; i < PreNumbers -1; i++)
  363. {
  364. anglePre += speedPre / longr * Math.Sin(b) * timeSpan;
  365. tempx += speedPre * Math.Cos(anglePre + b) * timeSpan;
  366. speedPre += acceleration * timeSpan;
  367. }
  368. WGS84Points endPointX = new WGS84Points();
  369. endPointX.x = endPoint.x;
  370. endPointX.y = startPoint.y;
  371. double distanceX = GetDistance(startPoint, endPointX);
  372. return tempx / distanceX;
  373. }
  374. /// <summary>
  375. /// 预测模型中X坐标比例系数,相对于当前坐标值的比例系数
  376. /// </summary>
  377. /// <param name="angleCur"></param>
  378. /// <param name="anglePid"></param>
  379. /// <param name="preAngle"></param>
  380. /// <param name="speedCur"></param>
  381. /// <param name="acceleration"></param>
  382. /// <param name="startPoint"></param>
  383. /// <param name="endPoint"></param>
  384. /// <returns></returns>
  385. private double PrePointFactorY(double angleCur, double anglePid, double speedCur,
  386. double acceleration, WGS84Points startPoint, WGS84Points endPoint)
  387. {
  388. double b = Math.Atan(longr / (longf + longr) * Math.Tan(anglePid));
  389. double speedPre = speedCur;
  390. double anglePre = angleCur;
  391. double tempy = 0;
  392. for (int i = 0; i < PreNumbers - 1; i++)
  393. {
  394. anglePre += speedPre / longr * Math.Sin(b) * timeSpan;
  395. tempy += speedPre * Math.Sin(anglePre + b) * timeSpan;
  396. speedPre += acceleration * timeSpan;
  397. }
  398. WGS84Points endPointY = new WGS84Points();
  399. endPointY.x = startPoint.x;
  400. endPointY.y = endPoint.y;
  401. double distanceY = GetDistance(startPoint, endPointY);
  402. return tempy / distanceY;
  403. }
  404. #endregion
  405. }
  406. /// <summary>
  407. /// 起始点事件
  408. /// </summary>
  409. public delegate void EventStartPointHandler(StartPointEventArgs e);
  410. public class StartPointEventArgs : EventArgs
  411. {
  412. public string Mesg { get; set; }
  413. public StartPointEventArgs(string value)
  414. {
  415. this.Mesg = value;
  416. }
  417. }
  418. }