C#实例(经典):四路光电开关&激光雷达数据采集和波形图绘制
前言:本文全部纯手工打造,如有疏漏之处,还请谅解!
如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! !
这篇文章涉及较多C#重要知识点,如果都能看懂,你至少可以算得上入门了!有兴趣的同志可以下载源码调试.
开始吧:
-》指令格式介绍
激光测距模块
UDP: 192.168.1.200 8008发往8010;192.168.1.201 8008发往8011;
协议:C3 00为195cm
光电开关模块
UDP:192.168.1.202 8008发往8012
帧头59 59
数据 01 01 01 01 为4个光电开关状态,依次为安检通道入口光电开关、安检门光电开关1、安检门光电开关2,安检通道出口光电开关。其中1为无人遮挡状态,0为有人遮挡状态
填充 44 55 66 77 88 99 00 12 23 34 45 56 67 ee
4个光电开关均无人
1、2、3光电开关有人 4光电开关无人
开发软硬件环境:
硬件:1. 4路光电开关,4路测距雷达,数据通过udp发送到主机192.168.1.119
软件:1. vs2017 + win10
-》重要知识点:
1. 多线程操作:thread和task的使用
2. winform的chart控件使用
3.队列Queue和list使用
4.双缓冲用法
5.定时器操作
6.线程中操作主窗体控件:
this.Invoke((EventHandler)delegate
{
richTextBoxEx1.Text += stringData + "\r\n";
}):
7.通过循环的方式遍历操作控件
8.数据类型转换:
Byte[] recv = client.Receive(ref endpoint);
string stringData = "0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
-》开发难点:
1. chart需要绘制所有采集上来的数据点,光电开关1毫秒就一组数据,绘图时间得跟得上
2. 多线程的灵活使用
全部代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting; namespace lidarTest
{
public partial class mainForm : DevComponents.DotNetBar.Office2007Form
{
public mainForm()
{
this.DoubleBuffered = true;//设置本窗体
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲 this.EnableGlass = false;
InitializeComponent();
InitChart();
checkBox2.Checked = false;
checkBox1.Checked = false;
}
private Queue<int>[] dataQueue = new Queue<int>[8];//把Queue<double>看成一个类型 int[] a=new int [8]
private List<int>[] dataList = new List<int>[8];
private Queue<string> dQueue = new Queue<string>();
bool isStart = false;
int count = 0;
private static readonly object Lock = new object();
Stopwatch elapsetime = new Stopwatch();
private void mainForm_Load(object sender, EventArgs e)
{
dataQueue[0] = new Queue<int>();
dataQueue[1] = new Queue<int>();
dataQueue[2] = new Queue<int>();
dataQueue[3] = new Queue<int>();
dataQueue[4] = new Queue<int>();
dataQueue[5] = new Queue<int>();
dataQueue[6] = new Queue<int>();
dataQueue[7] = new Queue<int>(); dataList[0] = new List<int>();
dataList[1] = new List<int>();
dataList[2] = new List<int>();
dataList[3] = new List<int>();
dataList[4] = new List<int>();
dataList[5] = new List<int>();
dataList[6] = new List<int>();
dataList[7] = new List<int>(); this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.Top = 0;
this.Left = 0;
this.Width = Screen.PrimaryScreen.WorkingArea.Width;
this.Height = Screen.PrimaryScreen.WorkingArea.Height;
Start(); //MessageBox.Show( DateTime.Now.ToString("yyyy_MM_dd_hh_mm_ss_fff"));
}
// 防止闪屏
//protected override CreateParams CreateParams
//{
// get
// {
// CreateParams cp = base.CreateParams;
// cp.ExStyle |= 0x02000000;
// return cp;
// }
//} public void Start()
{
Thread t1 = new Thread(StartDataRevThread1); //第一路激光雷达数据接收线程
t1.Start();
t1.IsBackground = true; Thread t2 = new Thread(StartDataRevThread2); //第二路激光雷达数据接收线程
t2.Start();
t2.IsBackground = true; Thread t3 = new Thread(StartDataRevThread3);//第三路激光雷达数据接收线程
t3.Start();
t3.IsBackground = true; Thread t4 = new Thread(StartDataRevThread4);////第四路激光雷达数据接收线程
t4.Start();
t4.IsBackground = true; Thread t5 = new Thread(StartDataRevThread5);//四个广电开关数据接受线程
t5.Start();
t5.IsBackground = true; Thread t6 = new Thread(dataSaveThread6);//数据写入线程
t6.Start();
t6.IsBackground = true;
}
private void StartDataRevThread1()
{
try
{
UdpClient client = new UdpClient(8021);
//IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);//
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.30"), 8008);
//client.Client.ReceiveBufferSize = 40960;//40960 默认值是8192
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx1.Text += stringData + "\r\n";
chartShow( recv[2] + (recv[3]<<8),1);
}
);
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace) ;
}
}
private void StartDataRevThread2()
{
try
{
UdpClient client = new UdpClient(8022);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.40"), 8008);
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx2.Text += stringData + "\r\n";
chartShow(recv[2] + (recv[3] << 8),2);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void StartDataRevThread3()
{
try
{
UdpClient client = new UdpClient(8023);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.100"), 8008);
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx3.Text += stringData + "\r\n";
chartShow( recv[2] + (recv[3] << 8),3);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void StartDataRevThread4()
{
try
{
UdpClient client = new UdpClient(8024);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.200"), 8008);
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
string stringData = "0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
this.Invoke((EventHandler)delegate
{
//richTextBoxEx4.Text += stringData + "\r\n";
chartShow( recv[2] + (recv[3] << 8),4);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
} private void StartDataRevThread5()
{
try
{
UdpClient client = new UdpClient(8012);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.202"), 8008);
client.Client.ReceiveBufferSize = 1024*1024;//默认值是8192
while (true)
{
Byte[] recv = client.Receive(ref endpoint);
elapsetime.Restart();//计时开始
this.Invoke((EventHandler)delegate
{
//if (count >= 100)
{
count = 0;
Task.Run(() =>
{
chartShow(recv[2], 5);
}
);
Task.Run(() =>
{
chartShow(recv[3], 6);
}
);
Task.Run(() =>
{
chartShow(recv[4], 7);
}
);
Task.Run(() =>
{
chartShow(recv[5], 8);
}
);
//chartShow(recv[2], 5);
//chartShow(recv[3], 6);
//chartShow(recv[4], 7);
//chartShow(recv[5], 8); if (checkBox2.Checked == true)
{
string stringData = "0x" + BitConverter.ToString(recv).Replace("-", " 0x").ToLower();
dQueue.Enqueue(DateTime.Now.ToString("yyyy-MM-dd_HH:mm:ss:fff") + " " + stringData);
} }
count++; } );
elapsetime.Stop();//计时结束
this.Invoke((EventHandler)delegate
{
label1.Text = "接收数据耗时:"+ elapsetime.ElapsedMilliseconds.ToString("0000");
});
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
}
private void dataSaveThread6()
{
while (true)
{
if (checkBox2.Checked == true)
{
String LogPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");
if (dQueue.Count() > 0)
strWrite(dQueue.Dequeue(), LogPath, "log.txt");
}
}
}
private void InitChart()
{
Chart[] ch = new Chart[12] { chart1, chart2, chart3, chart4,chart5, chart6, chart7, chart8 , chart_1, chart_2, chart_3, chart_4 };
for (int i = 0; i < 4 ; i++)
{
ch[i].ChartAreas.Clear();
ChartArea chartArea1 = new ChartArea("C1");
ch[i].ChartAreas.Add(chartArea1);
//定义存储和显示点的容器
ch[i].Series.Clear();
Series series1 = new Series("S1");
series1.ChartArea = "C1";
ch[i].Series.Add(series1); ch[i].ChartAreas[0].AxisY.IsStartedFromZero = false;
ch[i].Legends[0].Enabled = false; ch[i].ChartAreas[0].AxisX.Interval = 100;
ch[i].ChartAreas[0].AxisX.Maximum = 1000;
//ch[i].ChartAreas[0].AxisX.ScaleView.Size = 8;//设置图表可视区域数据点数,说白了一次可以看到多少个X轴区域 ch[i].ChartAreas[0].Axes[0].MajorGrid.Enabled = false;
ch[i].ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//y轴上网格
//ct.ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//ch[i].ChartAreas[0].AxisX.IsStartedFromZero = false;
//ch[i].ChartAreas[0].AxisX.MajorGrid.LineColor = System.Drawing.Color.Silver;
//ch[i].ChartAreas[0].AxisY.MajorGrid.LineColor = System.Drawing.Color.Silver;
//设置标题
ch[i].Titles.Clear();
//ch[i].Titles.Add("S01");
//ch[i].Titles[0].Text = "通道" + (i + 1) + " 折线图显示";
//ch[i].Titles[0].ForeColor = Color.RoyalBlue;
//ch[i].Titles[0].Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
//设置图表显示样式
ch[i].Series[0].Color = Color.Red;
//this.chart1.Titles[0].Text = string.Format("{0}折线图显示", );
ch[i].Series[0].ChartType = SeriesChartType.FastLine;
ch[i].Series[0].Points.Clear();
}
for (int i = 4; i < 12; i++)
{
ch[i].ChartAreas.Clear();
ChartArea chartArea1 = new ChartArea("C1");
ch[i].ChartAreas.Add(chartArea1);
//定义存储和显示点的容器
ch[i].Series.Clear();
Series series1 = new Series("S1");
series1.ChartArea = "C1";
ch[i].Series.Add(series1); ch[i].ChartAreas[0].AxisY.IsStartedFromZero = false;
ch[i].Legends[0].Enabled = false; //ch[i].ChartAreas[0].AxisX.Interval = 100;
//ch[i].ChartAreas[0].AxisX.Maximum = 10000;
//ch[i].ChartAreas[0].AxisX.ScaleView.Size = 8;//设置图表可视区域数据点数,说白了一次可以看到多少个X轴区域 ch[i].ChartAreas[0].Axes[0].MajorGrid.Enabled = false;
ch[i].ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//y轴上网格
//ct.ChartAreas[0].Axes[1].MajorGrid.Enabled = false;
//ch[i].ChartAreas[0].AxisX.IsStartedFromZero = false;
//ch[i].ChartAreas[0].AxisX.MajorGrid.LineColor = System.Drawing.Color.Silver;
//ch[i].ChartAreas[0].AxisY.MajorGrid.LineColor = System.Drawing.Color.Silver;
//设置标题
ch[i].Titles.Clear();
//ch[i].Titles.Add("S01");
//ch[i].Titles[0].Text = "通道" + (i + 1) + " 折线图显示";
//ch[i].Titles[0].ForeColor = Color.RoyalBlue;
//ch[i].Titles[0].Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
//设置图表显示样式
ch[i].Series[0].Color = Color.Red;
//this.chart1.Titles[0].Text = string.Format("{0}折线图显示", );
ch[i].Series[0].ChartType = SeriesChartType.FastLine;
ch[i].Series[0].Points.Clear();
}
} public void chartShow(int y, int ch)
{ Chart[] chNum = new Chart[8] { chart_1, chart_2, chart_3, chart_4, chart5, chart6, chart7, chart8 };
if (ch <= 8)
chartDisplay(chNum[ch - 1], ch, y); }
delegate void ChartDelegate(Chart chart, int ch, int y);
private void chartDisplay(Chart chart, int ch, int y)
{ if (chart.InvokeRequired)
{
ChartDelegate chartDelegate = chartDisplay;
chart.Invoke(chartDelegate, new object[] { chart, ch, y });
}
else
{
lock (Lock)
{
if (isStart == true)
UpdateQueueValue(ch, y);//点击开启按钮后,开始采集收集数据,并更新到队列或列表中 }
}
}
private void UpdateQueueValue(int ch, int y)
{
lock (Lock)
{
if (dataQueue[ch - 1].Count > 1000)
//先出列
dataQueue[ch - 1].Dequeue();
dataQueue[ch - 1].Enqueue(y);
//方法二 用list
//if (dataList[ch - 1].Count > 20000)
// dataList[ch - 1].RemoveAt(0); //dataList[ch - 1-4].Add(2);
dataList[ch - 1].Add(y);
}
}
private void btnStart_Click(object sender, EventArgs e)
{ if (!isStart)
{
dataQueue[0] = new Queue<int>();
dataQueue[1] = new Queue<int>();
dataQueue[2] = new Queue<int>();
dataQueue[3] = new Queue<int>();
dataQueue[4] = new Queue<int>();
dataQueue[5] = new Queue<int>();
dataQueue[6] = new Queue<int>();
dataQueue[7] = new Queue<int>(); dataList[0] = new List<int>();
dataList[1] = new List<int>();
dataList[2] = new List<int>();
dataList[3] = new List<int>();
dataList[4] = new List<int>();
dataList[5] = new List<int>();
dataList[6] = new List<int>();
dataList[7] = new List<int>(); chart_1.Series[0].Points.Clear();
chart_2.Series[0].Points.Clear();
chart_3.Series[0].Points.Clear();
chart_4.Series[0].Points.Clear();
chart5.Series[0].Points.Clear();
chart6.Series[0].Points.Clear();
chart7.Series[0].Points.Clear();
chart8.Series[0].Points.Clear(); btnStart.Text = @"停止采集";
btnStart.DisabledImage = btnStart.Image;
btnStart.Image = (Image)btnStart.PressedImage.Clone();
isStart = !isStart; }
else
{
btnStart.Text = @"开始采集";
btnStart.Image = btnStart.DisabledImage;
isStart = !isStart;
}
}
/*************文件写入函数**************/
private void strWrite(string str, string filePath, string fileName)
{
lock (Lock)
{
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
if (!File.Exists(filePath + "\\" + fileName))
File.Create(filePath + "\\" + fileName).Close(); //.Close 很关键,不然会有问题 StreamWriter sw = new StreamWriter(filePath + "\\" + fileName, true);//true 追加数据
sw.WriteLine(str);
sw.Close();
}
}
/*************chart图片保存函数**************/
private void imageSave( Chart chart, string filePath, string fileName)
{
lock (Lock)
{
if (!Directory.Exists(filePath))
Directory.CreateDirectory(filePath);
chart.SaveImage(filePath +"\\" + fileName, ChartImageFormat.Png);
}
} /*************定时器中更新chart**************/
private void timer1_Tick(object sender, EventArgs e)
{ Chart[] ch = new Chart[8] { chart1, chart2, chart3, chart4, chart5, chart6, chart7, chart8 };
Chart[] cha = new Chart[4] { chart_1, chart_2, chart_3, chart_4 };
string[] str = new string[8] { "chart1", "chart2", "chart3", "chart4", "chart5", "chart6", "chart7", "chart8" };
string[] stri = new string[4] { "chart_1", "chart_2", "chart_3", "chart_4", };
Label[] lb = new Label[4] { label2, label3, label4, label5 }; for (int j = 4; j < 8; j++)
{
Stopwatch sw = new Stopwatch();
var k = j;//参数需要传入task中,不然j一直是7
Task.Run(() =>
{ sw.Start();
this.Invoke((EventHandler)delegate
{
//chart5.Series[0].Points.Clear();
for (int i = 0; i < dataList[k].Count; i++)
ch[k].Series[0].Points.AddY(dataList[k][i]);//光电开关波形图-所有点
dataList[k].Clear(); ch[k-4].Series[0].Points.Clear();
for (int i = 0; i < dataQueue[k].Count; i++)
ch[k - 4].Series[0].Points.AddY(dataQueue[k].ElementAt(i));//光电开关波形图-最近1000个点 for (int i = 0; i < dataList[k-4].Count; i++)
cha[k - 4].Series[0].Points.AddY(dataList[k-4][i]);//激光测距雷达波形图--所有点
dataList[k-4].Clear(); if (checkBox1.Checked == true)
{
//保存曲线图片
String imagePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image//" + str[k]);
imageSave(ch[k], imagePath, DateTime.Now.ToString("yyyy_MM_dd_hh_mm_ss_fff") + ".png");
}
sw.Stop();
lb[k - 4].Text = sw.ElapsedMilliseconds.ToString(str[k] + "耗时:" + "0000");//记录chart绘制的好事呢
}); });
} } }
}
运行结果:
项目源码下载地址:
链接:https://pan.baidu.com/s/1QfoIVNarj-rgK449JM40yQ
提取码:v2nu
------------------------------------------------------------------------
如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! !
C#实例(经典):四路光电开关&激光雷达数据采集和波形图绘制的更多相关文章
- Emgu-WPF 激光雷达研究-移动物体跟踪
原文:Emgu-WPF 激光雷达研究-移动物体跟踪 接前两篇博客: 激光雷达数据解析并绘制雷达图 https://blog.csdn.net/u013224722/article/details/80 ...
- 第一个简单的Echarts实例
该示例使用 vue-cli 脚手架搭建 安装echarts依赖 npm install echarts -S 或者使用国内的淘宝镜像: 安装 npm install -g cnpm --registr ...
- 基于Oracle的SQL优化(社区万众期待 数据库优化扛鼎巨著)
基于Oracle的SQL优化(社区万众期待数据库优化扛鼎巨著) 崔华 编 ISBN 978-7-121-21758-6 2014年1月出版 定价:128.00元 856页 16开 编辑推荐 本土O ...
- PHP之:多图上传
撰写日期:2016-6-30 15:17:35 Thursday 参考 http://a3147972.blog.51cto.com/2366547/1381136 (08-05ThinkPHP+sw ...
- PS教程1000例
http://www.missyuan.com/thread-446934-1-1.html Photoshop绘制逼真头发发丝效果http://www.missyuan.com/thread-446 ...
- 2014图灵技术图书最受欢迎TOP15
来自:图灵社区昨晚给我发的邮件,感觉不错,和大家分享,mark下. [小编语] 回首2014,感谢小伙伴们一路相随.让我们2015一起更快乐地玩耍.今天小编为大家盘点一下过去2014年表现最给力的技术 ...
- LiDAR、LAS、LAS Dataset与点云
LiDAR Light Detection And Ranging,激光探测及测距,是一种光学遥感技术,使用激光对地球表面的密集采样,产生高精度X.Y.Z测量值. 激光雷达系统的主要硬件组成部分包括一 ...
- 最近学习工作流 推荐一个activiti 的教程文档
全文地址:http://www.mossle.com/docs/activiti/ Activiti 5.15 用户手册 Table of Contents 1. 简介 协议 下载 源码 必要的软件 ...
- Java 静态工厂模式的使用
多相关文章请参考:http://www.enjoytoday.cn/categorys/java 静态工厂模式给人的第一印象就是:static+abstract.这两个词汇已经说明了一切,一个是周期长 ...
随机推荐
- Pets(匈牙利算法)
Are you interested in pets? There is a very famous pets shop in the center of the ACM city. There ar ...
- HDU-Tick and Tick
The three hands of the clock are rotating every second and meeting each other many times everyday. F ...
- java初探(1)之防止库存为负以及防超买
在秒杀业务中,会出现当只剩一个库存时,但有多个人仍然秒杀成功,且都减库存成功,因此,在减库存,更新数据库的时候,需要在sql语句上进行判断,是否库存大于0. @Update("update ...
- 基于PHP实现CMS识别
最近正在开发一款基于PHP实现的Web安全检测平台,写到了CMS识别这一功能,便写一篇文章总结一下. 首先需要梳理的是CMS识别的几种方法: 1.网页源代码特征:例如源代码中包含CMS的名称或是某种特 ...
- linux下P2P协议(BitTorrent)-libtorrent库编译,测试
1.libtorrent 简介,下载和编译 libtorrent简介 libtorrent是功能齐全的C ++ bittorrent的p2p协议实现,专注于效率和可伸缩性.它可以在嵌入式设备和台式机上 ...
- i春秋公益赛之BFnote
题目链接:https://buuoj.cn/challenges#gyctf_2020_bfnote 首先检查程序开的保护: 发现程序只开了canary和NX保护,接下来查看IDA反汇编出来的为代码, ...
- VC 编译 MATLAB 的 mex 文件
VC 编译 MATLAB 的 mex 文件mex 文件是 MATLAB 调用其他程序设计语言程序或算法的接口.在 Windows 环境中,mex 文件是扩展文件名为 DLL 的动态链接库,可以在 m ...
- C#开发PACS医学影像三维重建(一):使用VTK重建3D影像
VTK简介: VTK是一个开源的免费软件系统,主要用于三维计算机图形学.图像处理和可视化.Vtk是在面向对象原理的基础上设计和实现的,它的内核是用C++构建的. 因为使用C#语言开发,而VTK是C++ ...
- 2020 计蒜之道 预赛 第三场 石子游戏(简单)(暴力DP)
石子游戏(简单) 原题链接 思路: 通过形式容易看出是一道DP.其中异或和的情况只有64种,所以我们可以开一维来记录当前异或和的状态. 利用dp[当前位置][异或和][是否选择当前]来进行状态转移.时 ...
- JELLY技术周刊 Vol.23: Vue3 是伟大航路上的 One Piece 么?
蒲公英 · JELLY技术周刊 Vol.23 这两天大家应该都被 Vue 发布 3.0 版本的信息刷屏了,背负着很多人的期待, Vue 终于将这个船新版本推到台前,接受大众的检验,那么这个代号为 On ...