SickTimEnc.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. using System.Text;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace Test
  10. {
  11. class SickTimEnc
  12. {
  13. //状态指示变量
  14. /// <summary>
  15. /// 指示初始化是否成功
  16. /// </summary>
  17. public bool initialized { get; set; }
  18. /// <summary>
  19. /// 指示是否工作中
  20. /// </summary>
  21. public bool working { get; set; }
  22. /// <summary>
  23. /// 指示是否检测到障碍物
  24. /// </summary>
  25. public bool obstacleDetected { get; set; }
  26. /// <summary>
  27. /// 发送指令返回值
  28. /// </summary>
  29. private int flag = 0;
  30. //通信参数
  31. private static readonly object Lock = new object();
  32. private IPAddress ipa;
  33. private int port;
  34. private TcpClient tcpClient;
  35. private NetworkStream stream;
  36. private int bufferSize = 16384;
  37. private const string startCmd = "02 73 52 4E 20 4C 4D 44 73 63 61 6E 64 61 74 61 03";
  38. private const string endCmd = "02 73 45 4E 20 4C 4D 44 73 63 61 6E 64 61 74 61 20 30 03";
  39. //防撞参数
  40. public int maxDataCount { get; set; }//最大保留历史数据个数
  41. public int left_range { get; set; } = 385;//325;//231;//271;//386;//366;
  42. public int right_range { get; set; } = 425;//485;//581;//541;//426;//446;
  43. private int ground_truth_height = 1700;//2200;//2300;//标准高度
  44. private int min_num_point_of_hinder = 30;//20;//判定为障碍物的最少点的数目
  45. private int min_obstacle_height = 500;//最小障碍物高度
  46. private int max_axis_Y = 2000;//2250;//画图时Y轴最大量程
  47. private List<string> originDatalist;//原始数据数组
  48. private List<int> validNum;//811个整型值
  49. private List<List<double>> validNumBuffer;//保存历史点云数据
  50. private List<List<double>> validNumBufferKalman;//保存经过kalman滤波的历史点云数据
  51. private List<double> listy;
  52. private List<double> listx;
  53. public List<double> yFiltered { get; set; }
  54. public List<double> yFilteredKalman { get; set; }
  55. //卡尔曼滤波参数
  56. private List<double> prevData, p, q, r, kGain;
  57. public SickTimEnc(string ip, int port)
  58. {
  59. initialized = false;
  60. maxDataCount = 3;
  61. originDatalist = new List<string>();
  62. validNum = new List<int>();
  63. validNumBuffer = new List<List<double>>();
  64. validNumBufferKalman = new List<List<double>>();
  65. prevData = new List<double>();
  66. p = new List<double>();
  67. q = new List<double>();
  68. r = new List<double>();
  69. kGain = new List<double>();
  70. for (int i = 0; i < right_range - left_range; i++)
  71. {
  72. prevData.Add(0);
  73. p.Add(450);
  74. q.Add(0.0001);
  75. r.Add(0.005);
  76. kGain.Add(0);
  77. }
  78. listy = new List<double>();
  79. listx = new List<double>();
  80. tcpClient = new TcpClient();
  81. if(!IPAddress.TryParse(ip, out ipa))
  82. {
  83. ipa = null;
  84. return;
  85. }
  86. try
  87. {
  88. tcpClient.Connect(ipa, port);
  89. stream = tcpClient.GetStream();
  90. }
  91. catch { return; }
  92. initialized = true;
  93. }
  94. /// <summary>
  95. /// 启动雷达处理数据
  96. /// </summary>
  97. public void work()
  98. {
  99. Task.Factory.StartNew(()=>
  100. {
  101. while (initialized)
  102. {
  103. try
  104. {
  105. if (working)
  106. {
  107. //开辟线程存储雷达原始数据字符串
  108. lock (Lock)
  109. {
  110. originDatalist.Clear();
  111. flag = sendCmd(startCmd);
  112. if (flag == 1)
  113. {
  114. byte[] buffer = new byte[bufferSize];
  115. stream.Read(buffer, 0, buffer.Length);
  116. string str = HexStringToASCII(buffer);
  117. originDatalist.Add(str);
  118. }
  119. if (originDatalist.Count != 0)
  120. {
  121. for (int i = 0; i < originDatalist.Count; i++)
  122. {
  123. string ss = trimDataStr(originDatalist[i], "sRA LMDscandata 1 ", " not defined 0 0 0");
  124. string[] data = ss.Split(' ');
  125. string number = data[22];
  126. int length = Convert.ToInt32(number, 16);
  127. int temp = 0;
  128. //int[] validNum = new int[length];
  129. //string aws = "";
  130. //获取所有距离数值
  131. validNum.Clear();
  132. listy.Clear();
  133. listx.Clear();
  134. for (int j = 0; j < length; j++)
  135. {
  136. try
  137. {
  138. temp = Convert.ToInt32(data[23 + j], 16);
  139. }
  140. catch { temp = ground_truth_height; Console.WriteLine("数据转换异常"); }
  141. validNum.Add(temp);
  142. }
  143. for (int j = 0; j < length; j++)
  144. {
  145. double x = validNum[j] * Math.Cos((-45 + 0.333 * j) * Math.PI / 180);
  146. double y = validNum[j] * Math.Sin((-45 + 0.333 * j) * Math.PI / 180);
  147. listy.Add(y);
  148. listx.Add(x);
  149. }
  150. validNumBuffer.Add(listy);
  151. validNumBufferKalman.Add(kalmanFilter(listy));
  152. while (validNumBufferKalman.Count > maxDataCount)
  153. {
  154. validNumBufferKalman.RemoveAt(0);
  155. validNumBuffer.RemoveAt(0);
  156. }
  157. if(validNumBufferKalman.Count == maxDataCount)
  158. {
  159. bool obstacle = false;
  160. yFiltered = dataFilter(validNumBuffer, out obstacle);
  161. yFilteredKalman = dataFilter(validNumBufferKalman, out obstacle);
  162. obstacleDetected = obstacle;
  163. }
  164. }
  165. }
  166. }
  167. Thread.Sleep(1);
  168. }
  169. else
  170. {
  171. //空闲状态
  172. Thread.Sleep(1000);
  173. }
  174. }
  175. catch (Exception e) { Thread.Sleep(500); Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); }
  176. }
  177. });
  178. }
  179. /// <summary>
  180. /// 暂停工作
  181. /// </summary>
  182. /// <param name="ctrl"></param>
  183. public void Pause(bool ctrl)
  184. {
  185. working = !ctrl;
  186. }
  187. /// <summary>
  188. /// 停止工作
  189. /// </summary>
  190. public void Stop()
  191. {
  192. working = false;
  193. flag = sendCmd(endCmd);
  194. if (stream != null)
  195. {
  196. stream.Close();
  197. }
  198. if (tcpClient != null)
  199. {
  200. tcpClient.Close();
  201. }
  202. }
  203. /// <summary>
  204. /// 向雷达发送指令
  205. /// </summary>
  206. /// <param name="cmd"></param>
  207. /// <returns></returns>
  208. private int sendCmd(string cmd)
  209. {
  210. try
  211. {
  212. if (cmd.Equals(startCmd))
  213. {
  214. byte[] byteStartCmd = HexStringToBinary(startCmd);
  215. string result = HexStringToASCII(byteStartCmd);
  216. byte[] b = Encoding.UTF8.GetBytes(result);
  217. stream.Write(b, 0, b.Length);
  218. return 1;
  219. }
  220. if (cmd.Equals(endCmd))
  221. {
  222. byte[] byteStartCmd = HexStringToBinary(endCmd);
  223. string result = HexStringToASCII(byteStartCmd);
  224. byte[] b = Encoding.UTF8.GetBytes(result);
  225. stream.Write(b, 0, b.Length);
  226. return 2;
  227. }
  228. }
  229. catch { return 0; }
  230. return 0;
  231. }
  232. /// <summary>
  233. /// 将一条十六进制字符串转换为ASCII
  234. /// </summary>
  235. /// <param name="hexstring">一条十六进制字符串</param>
  236. /// <returns>返回一条ASCII码</returns>
  237. private static string HexStringToASCII(byte[] bt)
  238. {
  239. //byte[] bt = HexStringToBinary(hexstring);
  240. string lin = "";
  241. for (int i = 0; i < bt.Length; i++)
  242. {
  243. lin = lin + bt[i] + " ";
  244. }
  245. string[] ss = lin.Trim().Split(new char[] { ' ' });
  246. char[] c = new char[ss.Length];
  247. int a;
  248. for (int i = 0; i < c.Length; i++)
  249. {
  250. a = Convert.ToInt32(ss[i]);
  251. c[i] = Convert.ToChar(a);
  252. }
  253. string b = new string(c);
  254. return b;
  255. }
  256. /// <summary>
  257. /// 16进制字符串转换为二进制数组
  258. /// </summary>
  259. /// <param name="hexstring">用空格切割字符串</param>
  260. /// <returns>返回一个二进制字符串</returns>
  261. private static byte[] HexStringToBinary(string hexstring)
  262. {
  263. string[] tmpary = hexstring.Trim().Split(' ');
  264. byte[] buff = new byte[tmpary.Length];
  265. for (int i = 0; i < buff.Length; i++)
  266. {
  267. buff[i] = Convert.ToByte(tmpary[i], 16);
  268. }
  269. return buff;
  270. }
  271. /// <summary>
  272. /// 截取数据段
  273. /// </summary>
  274. /// <param name="sourse"></param>
  275. /// <param name="startstr"></param>
  276. /// <param name="endstr"></param>
  277. /// <returns></returns>
  278. private static string trimDataStr(string sourse, string startstr, string endstr)
  279. {
  280. string result = string.Empty;
  281. int startindex, endindex;
  282. try
  283. {
  284. startindex = sourse.IndexOf(startstr);
  285. if (startindex == -1)
  286. {
  287. return result;
  288. }
  289. string tmpstr = sourse.Substring(startindex + startstr.Length);
  290. endindex = tmpstr.IndexOf(endstr);
  291. if (endindex == -1)
  292. {
  293. return result;
  294. }
  295. result = tmpstr.Remove(endindex);
  296. }
  297. catch (Exception) { }
  298. return result;
  299. }
  300. /// <summary>
  301. /// 平滑数据,识别障碍物
  302. /// </summary>
  303. /// <param name="y"></param>
  304. /// <param name="isObstacle"></param>
  305. /// <returns></returns>
  306. private List<double> dataFilter(List<List<double>> y, out bool isObstacle)
  307. {
  308. List<double> y_udt = new List<double>();
  309. isObstacle = false;
  310. int hinder_point_count = 0;
  311. for (int i = left_range; i < right_range; i++)
  312. {
  313. int hinder_frame_count = 0;
  314. for (int j = 0; j < y.Count; j++)
  315. {
  316. if (i != left_range && i != right_range - 1)
  317. {
  318. y[j][i] = (y[j][i - 1] + y[j][i] + y[j][i + 1]) / 3;//每个点的y为其和相邻两个点和的平均值
  319. }
  320. double d = Math.Abs(y[j][i] - ground_truth_height);
  321. if (d > min_obstacle_height)//300
  322. hinder_frame_count = hinder_frame_count + 1;
  323. }
  324. if (hinder_frame_count == y.Count)
  325. hinder_point_count = hinder_point_count + 1;
  326. y_udt.Add(y[y.Count - 1][i]);
  327. }
  328. if (hinder_point_count >= min_num_point_of_hinder)
  329. isObstacle = true;
  330. return y_udt;
  331. }
  332. /// <summary>
  333. /// 卡尔曼滤波
  334. /// </summary>
  335. /// <param name="data_in"></param>
  336. /// <returns></returns>
  337. private List<double> kalmanFilter(List<double> data_in)
  338. {
  339. for (int i = left_range; i < right_range; i++)
  340. {
  341. p[i - left_range] = p[i - left_range] + q[i - left_range];
  342. kGain[i - left_range] = p[i - left_range] / (p[i - left_range] + r[i - left_range]);
  343. data_in[i] = prevData[i - left_range] + (kGain[i - left_range] * (data_in[i] - prevData[i - left_range]));
  344. p[i - left_range] = (1 - kGain[i - left_range]) * p[i - left_range];
  345. prevData[i - left_range] = data_in[i];
  346. }
  347. return data_in;
  348. }
  349. }
  350. }