using snap7Enc; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; namespace Test { public partial class obstacleDetectionForm : Form { private SickTimEnc laserLeft; private SickTimEnc laserRight; private int max_axis_Y = 2600;//2250;//画图时Y轴最大量程 private List dataDispList; private List colors;//雷达数据颜色 private bool obstacleDetected; private const string leftTrue = "left: True "; private const string leftFalse = "left: False "; private const string rightTrue = "right: True "; private const string rightFalse = "right: False "; //************** plc相关参数 ************* /// /// PLC 连接状态flag /// public bool isConnected = false; /// /// plc中cpu类型 /// private const CpuType cpu = CpuType.S71500; /// /// PLC的IP地址 /// private const string ip = "192.168.0.1"; /// /// PLC的端口号 /// private const Int16 rack = 0; /// /// 工作站号 /// private const Int16 slot = 1; /// /// PLC S7连接对象 /// protected static Plc plc = null; /// /// 用于将写PLC指令排队的阻塞队列 /// private BlockingCollection writingBlockingCollection = new BlockingCollection(); /// /// 写线程,控制PLC写入频率 /// private Thread writeThread; /// /// 系统关闭 /// private bool closed; /// /// 读写锁 /// private static object readWriteLock = new object(); //写入频率 private const int writeFreq = 25; private const short DB = 30; private const short ZPosition = 8; private const short ZThreshold = 200; private const short ZStart = 10; private const short ZStop = 12; private const short ZPause = 14; private short ZPositionValue = 0; private short ZStartValue = 0; private short ZStopValue = 0; private short ZPauseValue = 0; private bool startGoingDown = false; private bool laserWorking = false; //流程控制 private void Start() { obstacleDetected = false; colors = new List(); colors.Add(Color.Red.Name); colors.Add(Color.Yellow.Name); colors.Add(Color.Cyan.Name); colors.Add(Color.Blue.Name); dataDispList = new List(); //初始化雷达与数据显示 Task.Factory.StartNew(() => { //laserLeft = new SickTimEnc("192.168.0.77", 2111); laserRight = new SickTimEnc("192.168.0.88", 2111); while (!IsHandleCreated) { Thread.Sleep(500); Console.WriteLine("等待初始化完成"); } this.Invoke(new Action(() => { InitChart(); if (laserLeft != null) { Pause(); laserLeft.SetLeftRange(65); laserLeft.SetRightRange(115); laserLeft.ground_truth_height = 4050; laserLeft.min_num_point_of_hinder = 20; laserLeft.min_obstacle_height = 100; tb_angleLeft.Text = "65"; tb_angleRight.Text = "115"; Pause(); List> temp = new List>(); temp.Add(laserLeft.yFiltered); temp.Add(laserLeft.yFilteredKalman); chartAddData(laserLeft.listx, temp, 1); } if (laserRight != null) { Pause(); laserRight.SetLeftRange(75); laserRight.SetRightRange(105); laserRight.ground_truth_height = 2200; laserRight.min_num_point_of_hinder = 20; laserRight.min_obstacle_height = 100; tb_angleLeft.Text = "75"; tb_angleRight.Text = "125"; Pause(); List> temp = new List>(); temp.Add(laserRight.yFiltered); temp.Add(laserRight.yFilteredKalman); chartAddData(laserRight.listx, temp, 2); } })); while (!closed) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); try { this.Invoke(new Action(() => { //for (int i = 0; i < dataDispList.Count; i++) //{ // updateChartData(dataDispList[i].x, dataDispList[i].y, i); //} if (dataDispList.Count >= 2) { if (laserLeft != null) { updateChartData(laserLeft.listx, laserLeft.yFiltered, 0); updateChartData(laserLeft.listx, laserLeft.yFilteredKalman, 1); //lb_obstacle.Text = " left:" + laserLeft.obstacleDetected + " "; lb_obstacle.Text = laserLeft.obstacleDetected ? leftTrue : leftFalse; //lb_obstacle.Text = " left:" + laserLeft.dataCount + " "; obstacleDetected = false || laserLeft.obstacleDetected; } if (laserRight != null) { updateChartData(laserRight.listx, laserRight.yFiltered, dataDispList.Count >=4 ?2:0); updateChartData(laserRight.listx, laserRight.yFilteredKalman, dataDispList.Count >= 4 ?3:1); //lb_obstacle.Text = (dataDispList.Count >= 4?lb_obstacle.Text:String.Empty)+"right:" + laserRight.obstacleDetected + " "; if (dataDispList.Count >= 4) lb_obstacle.Text += laserRight.obstacleDetected ? rightTrue : rightFalse; else lb_obstacle.Text = laserRight.obstacleDetected ? rightTrue : rightFalse; //lb_obstacle.Text += "right:" + laserRight.dataCount + " "; obstacleDetected = obstacleDetected || laserRight.obstacleDetected; } } })); } catch { Stop(); } sw.Stop(); Console.WriteLine("laser: " + sw.ElapsedMilliseconds + "ms"); Thread.Sleep(30); } }); ////************* PLC 相关逻辑 ************* //bool result = PLCConnect(); //if (!result) //{ // Console.WriteLine("PLC连接失败"); // Environment.Exit(0); //} //else //{ // MsgNode msg = new MsgNode(); // msg.db = DB; // msg.length = 2; // Task.Factory.StartNew(() => // { // while (!closed) // { // System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); // sw.Start(); // if (plc == null) // { // Thread.Sleep(1000); // continue; // } // msg.start = ZPosition; // ReadFromPLC(ref msg); // ZPositionValue = BitConverter.ToInt16(msg.value.ToArray(), 0); // msg.start = ZStart; // ReadFromPLC(ref msg); // ZStartValue = BitConverter.ToInt16(msg.value.ToArray(), 0); // msg.start = ZStop; // ReadFromPLC(ref msg); // ZStopValue = BitConverter.ToInt16(msg.value.ToArray(), 0); // msg.start = ZPause; // ReadFromPLC(ref msg); // ZPauseValue = BitConverter.ToInt16(msg.value.ToArray(), 0); // //Console.WriteLine("position, start, stop, pause: " + ZPositionValue + ", " + ZStartValue + ", " + ZStopValue + ", " + ZPauseValue); // if (ZPauseValue == 1) // { // Pause(); // //Console.WriteLine("暂停"); // } // else // { // Pause(); // //Console.WriteLine("恢复"); // } // //收到开始下降信号 // if (ZStartValue == 1 && ZStopValue != 1) // { // startGoingDown = true; // //Console.WriteLine("下降过程"); // } // else // { // startGoingDown = false; // //Console.WriteLine("非下降过程"); // } // //进入下降阶段 // if (startGoingDown && ZPositionValue > ZThreshold) // { // if (!laserWorking) // { // Console.WriteLine("启动雷达"); // //Start(); // laserWorking = true; // } // } // //下降结束复位工作状态 // if (laserWorking && ZStopValue == 1) // { // Console.WriteLine("雷达工作结束"); // laserWorking = false; // } // if (laserWorking) // { // MsgNode writeMsg = new MsgNode(); // writeMsg.db = 41; // writeMsg.length = 2; // writeMsg.start = 60; // byte[] temp = { 0, 0 }; // if (obstacleDetected) // temp[1] = 1; // WriteToPLC(writeMsg); // } // sw.Stop(); // Console.WriteLine("PLC: " + sw.ElapsedMilliseconds + "ms"); // Thread.Sleep(1000); // } // }); //} } /// /// 暂停雷达数据处理线程 /// private void Pause() { if (laserLeft != null) { laserLeft.Pause(); } if (laserRight != null) { laserRight.Pause(); } } /// /// 停止获取雷达数据,断开连接 /// private void Stop() { if (laserLeft != null) { laserLeft.Stop(); } if (laserRight != null) { laserRight.Stop(); } } public obstacleDetectionForm() { InitializeComponent(); Start(); } //界面按钮 private void button1_Click(object sender, EventArgs e) { Start(); } private void button3_Click(object sender, EventArgs e) { Pause(); } private void button2_Click(object sender, EventArgs e) { Stop(); //isok = true; //for (int i = 0; i < validdatalist.Count; i++) //{ // string temp = validdatalist[i]; // string[] tempdata = temp.Split(' '); // for (int j = 0; j < tempdata.Length; j++) // { // Log.WriteData("data" + i, tempdata[j]); // } //} //datalist.Clear(); //flag = sendCmd(endCmd); //Environment.Exit(0); //this.Close(); } /// /// 初始化图表 /// private void InitChart() { //定义图表区域 this.laserDataChart.ChartAreas.Clear(); ChartArea chartArea1 = new ChartArea("C1"); this.laserDataChart.ChartAreas.Add(chartArea1); //定义存储和显示点的容器 this.laserDataChart.Series.Clear(); //Series series1 = new Series("S1"); //series1.ChartArea = "C1"; //Series series2 = new Series("S2"); //series2.ChartArea = "C1"; //this.laserDataChart.Series.Add(series1); //this.laserDataChart.Series.Add(series2); //this.chart1. //设置图表显示样式 this.laserDataChart.ChartAreas[0].AxisY.IsReversed = true; this.laserDataChart.ChartAreas[0].AxisY.Minimum = 0; this.laserDataChart.ChartAreas[0].AxisY.Maximum = max_axis_Y; this.laserDataChart.ChartAreas[0].AxisY.Interval = 50; this.laserDataChart.ChartAreas[0].AxisX.Minimum = -2500;// -200; this.laserDataChart.ChartAreas[0].AxisX.Maximum = 2500;// 200; this.laserDataChart.ChartAreas[0].AxisX.Interval = 100;// 100; this.laserDataChart.ChartAreas[0].AxisX.MajorGrid.LineColor = System.Drawing.Color.Silver; this.laserDataChart.ChartAreas[0].AxisY.MajorGrid.LineColor = System.Drawing.Color.Silver; this.laserDataChart.ChartAreas[0].AxisY.Title = "Y"; this.laserDataChart.ChartAreas[0].AxisX.Title = "X"; //this.chart1.ChartAreas[0].AxisX.ArrowStyle = AxisArrowStyle.Triangle; //this.chart1.ChartAreas[0].AxisY.ArrowStyle = AxisArrowStyle.Triangle; //设置标题 this.laserDataChart.Titles.Clear(); this.laserDataChart.Titles.Add("S01"); this.laserDataChart.Titles[0].Text = "雷达显示"; this.laserDataChart.Titles[0].ForeColor = Color.RoyalBlue; this.laserDataChart.Titles[0].Font = new System.Drawing.Font("Microsoft Sans Serif", 12F); ////设置图表显示样式 //this.laserDataChart.Series[0].Color = Color.Red; //this.laserDataChart.Series[0].ChartType = SeriesChartType.Line; //this.laserDataChart.Series[1].Color = Color.Blue; //this.laserDataChart.Series[1].ChartType = SeriesChartType.Line; ////List dis = lineFit3(listy); //for (int i = left_range; i < right_range; i++) //{ // //this.chart1.Series[0].Points.AddXY(listx[i], max_axis_Y - listy[i - left_range]);//listy[i - left_range] // //this.chart1.Series[1].Points.AddXY(listx[i], max_axis_Y - templisty[i - left_range]); // this.laserDataChart.Series[0].Points.AddXY(listx[i], listy[i - left_range]);//listy[i - left_range] // this.laserDataChart.Series[1].Points.AddXY(listx[i], templisty[i - left_range]); //} } /// /// 向图表中增加数据 /// /// x轴数据 /// y轴数据包 /// 雷达编号 public void chartAddData(List listx, List> listys, int laserIndex) { if (laserIndex != 1 && laserIndex != 2) return; int index = laserDataChart.Series.Count; for (int i = 0; i < listys.Count; i++) { Series series = new Series("S" + index+i); series.ChartArea = "C1"; laserDataChart.Series.Add(series); laserDataChart.Series[index + i].Color = Color.FromName(colors[index + i]); laserDataChart.Series[index + i].ChartType = SeriesChartType.Line; int left = 0; int right = 0; if (laserIndex == 1) { left = laserLeft.GetLeftRange("index"); right = laserLeft.GetRightRange("index"); } else { left = laserRight.GetLeftRange("index"); right = laserRight.GetRightRange("index"); } if (listx != null && listys[i] != null && listx.Count >= right && listys[i].Count >= right - left) { for (int j = left; j < right; j++) { laserDataChart.Series[index + i].Points.AddXY(listx[j], listys[i][j - left]); } } dataDispList.Add(new DispMsg(laserDataChart.Series[index + i], left, right, listx, listys[i])); } } /// /// 更新图表数据 /// /// /// /// public void updateChartData(List listx, List listy, int index) { try { dataDispList[index].series.Points.Clear(); for (int j = dataDispList[index].left; j < dataDispList[index].right; j++) { if (listx != null && listy != null && listx.Count >= dataDispList[index].right && listy.Count >= dataDispList[index].right - dataDispList[index].left) { //Console.WriteLine(listx.Count + ", " + listy.Count + ", " + j + ", " + dataDispList[index].left); double x = listx[j]; double y = listy[j - dataDispList[index].left]; //dataDispList[index].series.Points.AddXY(listx[j], listy[j-dataDispList[index].left]); dataDispList[index].series.Points.AddXY(x, y); } } } catch(Exception e) { Console.WriteLine(e.StackTrace); } } ///// ///// 线性拟合 ///// ///// ///// ///// //private static List lineFit(List x, List y) //{ // double a, b, c; // int size = x.Count; // if (size < 2) // { // a = 0; // b = 0; // c = 0; // return null; // } // double x_mean = 0; // double y_mean = 0; // for (int i = 0; i < size; i++) // { // x_mean += x[i]; // y_mean += y[i]; // } // x_mean /= size; // y_mean /= size; //至此,计算出了 x y 的均值 // double Dxx = 0, Dxy = 0, Dyy = 0; // for (int i = 0; i < size; i++) // { // Dxx += (x[i] - x_mean) * (x[i] - x_mean); // Dxy += (x[i] - x_mean) * (y[i] - y_mean); // Dyy += (y[i] - y_mean) * (y[i] - y_mean); // } // double lambda = ((Dxx + Dyy) - Math.Sqrt((Dxx - Dyy) * (Dxx - Dyy) + 4 * Dxy * Dxy)) / 2.0; // double den = Math.Sqrt(Dxy * Dxy + (lambda - Dxx) * (lambda - Dxx)); // a = Dxy / den; // b = (lambda - Dxx) / den; // c = -a * x_mean - b * y_mean; // Console.WriteLine(a + " " + b + " " + c); // dis = new List(); // errorIndex.Clear(); // for (int i = 0; i < size; i++) // { // if (y[i] < (-a * x[i] - c) / b) // { // double d = Math.Abs(a * x[i] + b * y[i] + c) / Math.Sqrt(a * a + b * b); // if (d > 40) // { // dis.Add(d); // errorIndex.Add(i); // } // //Log.WriteLog(LogType.PROCESS, d + ""); // } // } // return dis; //} //private static List lineFit2(List y) //{ // double b; // int size = y.Count; // if (size < 2) // { // b = 0; // return null; // } // double sum = 0; // for(int i = 0; i < size; i++) // { // sum += y[i]; // } // b = sum / size; // dis = new List(); // errorIndex.Clear(); // for (int i = 0; i < size; i++) // { // if (y[i] < b) // { // double d = Math.Abs(y[i] - b); // if (d > 40) // { // dis.Add(d); // errorIndex.Add(i); // } // } // } // return dis; //} ///// ///// 是否有障碍物 ///// ///// ///// ///// //private static List lineFit3(List y) //{ // double b; // int size = y.Count; // if (size < 2) // { // b = 0; // return null; // } // double sum = 0; // for (int i = left_range; i < right_range; i++) // { // sum += y[i]; // } // b = sum / (right_range - left_range); // dis = new List(); // errorIndex.Clear(); // for (int i = left_range; i < right_range; i++) // { // double d = Math.Abs(y[i] - b); // if (d > 20) // { // double y_update = 0; // dis.Add(y_update); // errorIndex.Add(i); // } // else // { // dis.Add(y[i]); // } // } // return dis; //} //private static bool IsHinder(List testdata, double deviation) //{ // bool isHinder = true; // //Data errordata = new Data(); // List recorddata = new List(); // for (int i = 0; i < testdata.Count; i++) // { // if (testdata[i] > deviation) // { // //errordata.key = i; // //errordata.value = testdata[i]; // //Console.WriteLine(i + " " + testdata[i]); // recorddata.Add(i); // } // } // if (recorddata.Count <= 5 || IsBorderUpon(recorddata, 10) < 1) // { // isHinder = false; // } // return isHinder; //} ///// ///// 连续判断 ///// ///// ///// ///// //private static int IsBorderUpon(List arr, int num) //{ // var query = arr.OrderBy(p => p).Aggregate>>(null, (m, n) => // { // if (m == null) return new List>() { new List() { n } }; // if (m.Last().Last() != n - 1) // { // m.Add(new List() { n }); // } // else // { // m.Last().Add(n); // } // return m; // }); // int flag = 0; // for (int i = 0; i < query.Count; i++) // { // if (query[i].Count > 5) // { // flag++; // } // } // return flag; //} //********************** PLC **************************** /// /// 连接PLC /// /// private bool PLCConnect() { closed = false; writeThread = new Thread(() => { //Stopwatch stopwatch = new Stopwatch(); while (!closed) { //stopwatch.Restart(); bool result = WriteAccordingly(); if (!result) Console.WriteLine("写PLC操作异常"); Thread.Sleep(1000 / writeFreq); //stopwatch.Stop(); //Console.WriteLine(stopwatch.ElapsedMilliseconds / 1000.0f); } }); writeThread.IsBackground = true; writeThread.Priority = ThreadPriority.AboveNormal; writeThread.Start(); if (plc == null) { plc = new Plc(cpu, ip, rack, slot); } if (plc != null) { ErrorCode err = plc.Open(); if (err != ErrorCode.NoError) { Console.WriteLine("connection error"); isConnected = false; } else { Console.WriteLine("connected"); isConnected = true; } } else { isConnected = false; } return isConnected; } /// /// 关闭PLC连接 /// private void PLCDisconnect() { //try //{ // if (writeThread != null) // writeThread.Abort(); //} //catch (Exception ex) { Console.WriteLine("强制终止写PLC线程," + ex.Message); } closed = true; if (plc != null) { plc.Close(); } } /// /// 从阻塞队列获取需写入PLC数据并写入PLC,时间间隔在线程中控制 /// /// private bool WriteAccordingly() { MsgNode msg = null; try { msg = writingBlockingCollection.Take(); //Console.WriteLine("取出后," + writingBlockingCollection.Count); } catch (Exception ex) { Console.WriteLine("获取PLC写对象异常," + ex.Message); } if (msg == null || !msg.valid) { Console.WriteLine("msg is null or invalid"); return false; } //更新设备状态 isConnected = plc.IsConnected; if (isConnected) { lock (readWriteLock) { plc.WriteBytes(DataType.DataBlock, msg.db, msg.start, msg.value.ToArray()); } } else { Console.WriteLine("掉线"); return false; } return true; } /// /// 读取PLC数据块 /// /// /// /// private void ReadFromPLC(ref MsgNode msg) { //更新设备状态 isConnected = plc.IsConnected; List result = new List(); if (!isConnected) { PLCConnect(); } if (isConnected) { lock (readWriteLock) { msg.value = plc.ReadBytes(DataType.DataBlock, msg.db, msg.start, msg.length).ToList(); if (msg.value.Count != msg.length) { msg.valid = false; } msg.value.Reverse(); } } } /// /// 写入PLC,只支持1,2或4字节 /// /// /// /// private bool WriteToPLC(MsgNode msg) { //更新设备状态 isConnected = plc.IsConnected; if (msg != null && isConnected) { msg.value.Reverse(); writingBlockingCollection.Add(msg); //Console.WriteLine("加入后," + writingBlockingCollection.Count); return true; } else return false; } public class MsgNode : ICloneable { public int db; public int start; public int length; public List value; public bool valid; public MsgNode(int db, int start, int length, List value) { this.db = db; this.start = start; this.length = length; if (value != null && value.Count != length) { valid = false; } else { valid = true; } this.value = value; } public MsgNode() : this(0, 0, 0, new List()) { } public object Clone() { MsgNode obj = new MsgNode(); obj.db = db; obj.start = start; obj.length = length; obj.value = new List(value); obj.valid = valid; return obj; } } public class DispMsg { public Series series; public int left; public int right; public List x; public List y; public DispMsg(Series series, int left, int right, List x, List y) { this.series = series; this.left = left; this.right = right; this.x = x; this.y = y; } } } }