using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Test { class SickTimEnc { //状态指示变量 /// /// 指示初始化是否成功 /// public bool initialized { get; set; } /// /// 指示是否工作中 /// public bool working { get; set; } /// /// 指示是否检测到障碍物 /// public bool obstacleDetected { get; set; } /// /// 发送指令返回值 /// private int flag = 0; public int dataCount = 0; //通信参数 private readonly object Lock = new object(); private IPAddress ipa; private int port; private TcpClient tcpClient; private NetworkStream stream; private int bufferSize = 16384; private const string startCmd = "02 73 52 4E 20 4C 4D 44 73 63 61 6E 64 61 74 61 03"; private const string endCmd = "02 73 45 4E 20 4C 4D 44 73 63 61 6E 64 61 74 61 20 30 03"; private static char[] prefix = "sRA LMDscandata 1 ".ToCharArray(); private static char[] postfix = " not defined 0 0 0".ToCharArray(); //防撞参数 public int maxDataCount { get; set; }//最大保留历史数据个数 private int left_range = 385;//325;//231;//271;//386;//366; private int right_range = 425;//485;//581;//541;//426;//446; public int ground_truth_height { get; set; } = 2200;//2200;//2300;//标准高度 public int min_num_point_of_hinder { get; set; } = 30;//20;//判定为障碍物的最少点的数目 public int min_obstacle_height { get; set; } = 500;//最小障碍物高度 private List originDatalist;//原始数据数组 private List validNum;//811个整型值 private List> validNumBuffer;//保存历史点云数据 private List> validNumBufferKalman;//保存经过kalman滤波的历史点云数据 private List listy; public List listx { get; set; } public List yFiltered { get; set; } public List yFilteredKalman { get; set; } //卡尔曼滤波参数 private List prevData, p, q, r, kGain; public SickTimEnc(string ip, int port) { initialized = false; maxDataCount = 3; originDatalist = new List(); validNum = new List(); validNumBuffer = new List>(); validNumBufferKalman = new List>(); prevData = new List(); p = new List(); q = new List(); r = new List(); kGain = new List(); for (int i = 0; i < right_range - left_range; i++) { prevData.Add(0); p.Add(450); q.Add(0.0001); r.Add(0.005); kGain.Add(0); } listy = new List(); listx = new List(); tcpClient = new TcpClient(); if(!IPAddress.TryParse(ip, out ipa)) { ipa = null; return; } try { tcpClient.Connect(ipa, port); stream = tcpClient.GetStream(); } catch { return; } initialized = true; working = true; work(); } /// /// 暂停工作 /// /// public void Pause() { working = !working; } /// /// 停止工作 /// public void Stop() { working = false; flag = sendCmd(endCmd); if (stream != null) { stream.Close(); } if (tcpClient != null) { tcpClient.Close(); } } /// /// 获取最小角度阈值,范围-45 - 225 /// /// 类型,点编号index或角度degree /// public int GetLeftRange(string type) { if (type == "degree") return left_range / 3 - 45; else return left_range; } /// /// 获取最大角度阈值,范围-45 - 225 /// /// 类型,点编号index或角度degree /// public int GetRightRange(string type) { if (type == "degree") return right_range / 3 - 45; else return right_range; } ///// ///// 获取距地面高度 ///// ///// //public int GetHeight() //{ // return ground_truth_height; //} /// /// 设置最小角度阈值 /// /// public void SetLeftRange(int degree) { if (working) { working = false; lock (Lock) { left_range = (degree + 45) * 3; } working = true; } else { left_range = (degree + 45) * 3; } initKalman(); } /// /// 设置最大角度阈值 /// /// public void SetRightRange(int degree) { if (working) { working = false; lock (Lock) { right_range = (degree + 45) * 3; } working = true; } else { right_range = (degree + 45) * 3; } initKalman(); } ///// ///// 设置距地面高度 ///// ///// //public void SetHeight(int height) //{ // ground_truth_height = height; //} /// /// 初始化kalman滤波参数 /// private void initKalman() { prevData.Clear(); p.Clear(); q.Clear(); r.Clear(); kGain.Clear(); for (int i = 0; i < right_range - left_range; i++) { prevData.Add(0); p.Add(450); q.Add(0.0001); r.Add(0.005); kGain.Add(0); } } /// /// 启动雷达处理数据 /// private void work() { Task.Factory.StartNew(()=> { while (initialized) { try { if (working) { //System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); //sw.Start(); //开辟线程存储雷达原始数据字符串 lock (Lock) { originDatalist.Clear(); flag = sendCmd(startCmd); if (flag == 1) { byte[] buffer = new byte[bufferSize]; stream.Read(buffer, 0, buffer.Length); //string str = HexStringToASCII(buffer); originDatalist.Add(buffer); } if (originDatalist.Count != 0) { System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch(); sw1.Start(); List result = new List(); for (int i = 0; i < originDatalist.Count; i++) { //string ss = trimDataStr(originDatalist[i], "sRA LMDscandata 1 ", " not defined 0 0 0"); bool trimResult = trimData(originDatalist[i], out result); if (!trimResult) continue; //string[] data = ss.Split(' '); //string number = data[22]; byte[] lengthArr = { 32, 51, 50, 66 }; int index = 0,index2 = 0, length=0; while(index < 500 && index2 < lengthArr.Length) { if (result[index] == lengthArr[index2]) index2++; index++; } if (index2 < lengthArr.Length) continue; else length = 811; //while (result[index] != ' ') //{ // byte currByte = result[index]; // length = (length << 4) + (currByte<='9'?(currByte-48):(currByte-55)); // index++; //} //result[22]/10 * 16 + result[22] % 10;//Convert.ToInt32(number, 16); int temp = 0; //int[] validNum = new int[length]; //string aws = ""; //获取所有距离数值 validNum.Clear(); listy.Clear(); listx.Clear(); for (int j = 0; j < length; j++) { try { temp = -1; //temp = result[23+j] / 10 * 16 + result[23+j] % 10;//Convert.ToInt32(data[23 + j], 16); while(result[index] == ' ') { index++; } while (result[index] != ' ') { byte currByte = result[index]; temp = ((temp==-1?0:temp) << 4) + (currByte <= '9' ? (currByte - 48) : (currByte - 55)); index++; } if (temp == -1) continue; } catch { temp = ground_truth_height; Console.WriteLine("数据转换异常"); } validNum.Add(temp); } //Console.WriteLine("valid points: "+validNum.Count); for (int j = 0; j < length; j++) { double x = validNum[j] * Math.Cos((-45 + 0.333 * j) * Math.PI / 180); double y = validNum[j] * Math.Sin((-45 + 0.333 * j) * Math.PI / 180); listy.Add(y); listx.Add(x); } validNumBuffer.Add(listy); validNumBufferKalman.Add(kalmanFilter(listy)); while (validNumBufferKalman.Count > maxDataCount) { validNumBufferKalman.RemoveAt(0); validNumBuffer.RemoveAt(0); } if (validNumBufferKalman.Count == maxDataCount) { bool obstacle = false; yFiltered = dataFilter(validNumBuffer, out obstacle); yFilteredKalman = dataFilter(validNumBufferKalman, out obstacle); obstacleDetected = obstacle; } //sw.Stop(); //Console.WriteLine("laserData: " + sw.ElapsedMilliseconds + "ms"); //dataCount++; //Console.WriteLine("laser:: "+dataCount); } sw1.Stop(); Console.WriteLine("laserDataFilter: " + sw1.ElapsedMilliseconds + "ms"); } } Thread.Sleep(1); } else { //空闲状态 Thread.Sleep(1000); } } catch (Exception e) { Thread.Sleep(500); Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } } }); } /// /// 向雷达发送指令 /// /// /// private int sendCmd(string cmd) { try { if (cmd.Equals(startCmd)) { byte[] byteStartCmd = HexStringToBinary(startCmd); string result = HexStringToASCII(byteStartCmd); byte[] b = Encoding.UTF8.GetBytes(result); stream.Write(b, 0, b.Length); return 1; } if (cmd.Equals(endCmd)) { byte[] byteStartCmd = HexStringToBinary(endCmd); string result = HexStringToASCII(byteStartCmd); byte[] b = Encoding.UTF8.GetBytes(result); stream.Write(b, 0, b.Length); return 2; } } catch { return 0; } return 0; } /// /// 将一条十六进制字符串转换为ASCII /// /// 一条十六进制字符串 /// 返回一条ASCII码 private static string HexStringToASCII(byte[] bt) { //byte[] bt = HexStringToBinary(hexstring); string lin = ""; for (int i = 0; i < bt.Length; i++) { lin = lin + bt[i] + " "; } string[] ss = lin.Trim().Split(new char[] { ' ' }); char[] c = new char[ss.Length]; int a; for (int i = 0; i < c.Length; i++) { a = Convert.ToInt32(ss[i]); c[i] = Convert.ToChar(a); } string b = new string(c); return b; } /// /// 16进制字符串转换为二进制数组 /// /// 用空格切割字符串 /// 返回一个二进制字符串 private static byte[] HexStringToBinary(string hexstring) { string[] tmpary = hexstring.Trim().Split(' '); byte[] buff = new byte[tmpary.Length]; for (int i = 0; i < buff.Length; i++) { buff[i] = Convert.ToByte(tmpary[i], 16); } return buff; } /// /// 截取数据段 /// /// /// /// /// private static string trimDataStr(string sourse, string startstr, string endstr) { string result = string.Empty; int startindex, endindex; try { startindex = sourse.IndexOf(startstr); if (startindex == -1) { return result; } string tmpstr = sourse.Substring(startindex + startstr.Length); endindex = tmpstr.IndexOf(endstr); if (endindex == -1) { return result; } result = tmpstr.Remove(endindex); } catch (Exception) { } return result; } /// /// 截取数据段 /// /// /// /// /// private static bool trimData(byte[] source, out List result) { int i = 0, j = 0, k=postfix.Length-1; int left = 0, right = 0; result = new List(); //find prefix index while (j < prefix.Length && i= prefix.Length) left = i; else return false; //find postfix index i = source.Length - 1; while(k>=0 && i >= left) { if (postfix[k] == source[i]) k--; i--; } if (k < 0) right = i; else return false; for (int x = left; x <= right; x++) { result.Add(source[x]); } return true; } /// /// 平滑数据,识别障碍物 /// /// /// /// private List dataFilter(List> y, out bool isObstacle) { List y_udt = new List(); isObstacle = false; int hinder_point_count = 0; for (int i = left_range; i < right_range; i++) { int hinder_frame_count = 0; for (int j = 0; j < y.Count; j++) { if (i != left_range && i != right_range - 1) { y[j][i] = (y[j][i - 1] + y[j][i] + y[j][i + 1]) / 3;//每个点的y为其和相邻两个点和的平均值 } double d = Math.Abs(y[j][i] - ground_truth_height); if (d > min_obstacle_height)//300 hinder_frame_count = hinder_frame_count + 1; } if (hinder_frame_count == y.Count) hinder_point_count = hinder_point_count + 1; y_udt.Add(y[y.Count - 1][i]); } if (hinder_point_count >= min_num_point_of_hinder) isObstacle = true; return y_udt; } /// /// 卡尔曼滤波 /// /// /// private List kalmanFilter(List data_in) { for (int i = left_range; i < right_range; i++) { p[i - left_range] = p[i - left_range] + q[i - left_range]; kGain[i - left_range] = p[i - left_range] / (p[i - left_range] + r[i - left_range]); data_in[i] = prevData[i - left_range] + (kGain[i - left_range] * (data_in[i] - prevData[i - left_range])); p[i - left_range] = (1 - kGain[i - left_range]) * p[i - left_range]; prevData[i - left_range] = data_in[i]; } return data_in; } } }