C#实例:四路激光测距雷达数据采集和波形图绘制
1.所述产品 产品型号:TFmini Plus
相关资料下载地址:http://www.benewake.com/download
产品名称:TFmini Plus激光雷达模组 制造商 公司:北醒(北京)光子科技有限公司
2.产品功能:TFmini Plus是基于TFmini的升级项目,它是一款小型化,单点测距的产品,基于TOF(飞行 时间)原理,配合独特的光学、电学、算法设计,主要实现稳定、精准、高灵敏度和高速的距离测 量的功能。产品本身除了具有TFmini的低成本、小体积、测距远等特点外,还增加了IP65等级防 护,测距精度更高,对于室外强光、不同温度、不同反射率等不同环境下适应性更强,更低功耗, 探测频率也更加灵活。产品同时兼容UART和I2C通信接口,可通过指令进行切换
3. 串口数据通信 TFmini Plus串口数据通信,详见表 66。 表 6 TFmini Plus数据通信协议——UART
通信接口 UART 默认波特率 115200 数据位 8 停止位 1 奇偶校验 None 4. 串口数据输出格式及编码
TFmini Plus 有两种数据输出格式,标准数据输出格式和字符串数据格式,两种格式可通过指 令代码相互切换。
-。标准数据输出格式(默认) : 数据结构:数据帧长度为9字节。包含距离信息(Distance)、信号强度信息(Strength)、温度 (Temp)、数据校验字节(Checksum)等。数据格式为16进制(HEX)。具体数据编码详见下表:
-。字符串数据格式(Pix Mode) 以字符串形式输出,单位为m,比如测距为1.21m,则输出字符串1.21,后跟转义字符rn。此数据格式针对Ardupilot固件版本v3.6.2以下。如果您的Ardupilot固件版本大于或等于v3.6.2 可以直接使用标准数据格式。 5 输出数据说明
Dist(Distance):
代表TFmini Plus测量输出的距离值,默认单位为cm,解析为十进制的值范围 为0-1200。实际使用过程中,当信号强度值Strength<100或等于65535时,Dist的测量值被认为不 可信,默认输出0。
Strength:
指信号强度,默认输出值会在0-65535之间。当测距档位一定时,测距越远,信号 强度越低;目标物反射率越低,信号强度越低。当Strength大于100且不等于65535时,认为Dist 的测量值可信,客户可以根据使用场景自行调整。
Temp(Temperature):
表征芯片内部温度值。摄氏度 = Temp / 8 - 256
实例说明:开启四个线程分别接收四路激光测距雷达的数据并生成chart波形图
实例代码:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
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();
}
private Queue<double>[] dataQueue = new Queue<double>[4];//把Queue<double>看成一个类型 int[] a=new int [8]
bool isStart = false;
private void mainForm_Load(object sender, EventArgs e)
{
dataQueue[0] = new Queue<double>(100);
dataQueue[1] = new Queue<double>(100);
dataQueue[2] = new Queue<double>(100);
dataQueue[3] = new Queue<double>(100);
//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();
}
// 防止闪屏
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;
}
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 + "rn";
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 + "rn";
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 + "rn";
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 + "rn";
chartShow( recv[2] + (recv[3] << 8),4);
}
);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "n" + ex.StackTrace);
}
}
private void InitChart()
{
Chart[] ch = new Chart[4] { chart1, chart2, chart3, chart4};
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 = 5;
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.Line;
ch[i].Series[0].Points.Clear();
}
}
public void chartShow(Double y, int ch)
{
Chart[] chNum = new Chart[4] { chart1, chart2, chart3, chart4 };
if (ch <= 8)
chartDisplay(chNum[ch - 1], ch, y);
}
delegate void ChartDelegate(Chart chart, int ch, Double y);
private void chartDisplay(Chart chart, int ch, Double y)
{
if (chart.InvokeRequired)
{
ChartDelegate chartDelegate = chartDisplay;
chart.Invoke(chartDelegate, new object[] { chart, ch, y });
}
else
{
if (isStart == true)
UpdateQueueValue(ch, y);
chart.Series[0].Points.Clear();
for (int i = 0; i < dataQueue[ch - 1].Count; i++)
chart.Series[0].Points.AddXY((i + 1), dataQueue[ch - 1].ElementAt(i));
}
}
private void UpdateQueueValue(int ch, Double y)
{
if (dataQueue[ch - 1].Count > 100)
//先出列
dataQueue[ch - 1].Dequeue();
dataQueue[ch - 1].Enqueue(y);
}
private void btnStart_Click(object sender, EventArgs e)
{
if (!isStart)
{
btnStart.Text = @"停止采集";
btnStart.DisabledImage = btnStart.Image;
btnStart.Image = (Image)btnStart.PressedImage.Clone();
isStart = !isStart;
}
else
{
btnStart.Text = @"开始采集";
btnStart.Image = btnStart.DisabledImage;
isStart = !isStart;
}
}
}
}
运行结果:
源代码和激光雷达相关说明文档百度网盘下载地址:
链接:https://pan.baidu.com/s/1KmIbP1I9Eq90bcFOiYSI6w
提取码:ska8
- 如何快速查看github代码库中第一次commit的记录
- 更换包管理工具npm为yarn
- 【精选】使用Cryptory分析影响加密货币价格的因素(区块链系列3)
- React -- 组件间通信
- 图片和视频防盗链简单介绍
- 对比cp和scp命令 将数据从一台linux服务器复制到另一台linux服务器
- laravel—用Migration的操作数据库
- 有货移动Web端性能优化探索实践
- webpack打包速度和性能再次优化
- MySQL 清除表空间碎片
- 解决ios不支持按钮:active伪类的方法
- HTTP-FLV直播初探
- BZOJ1058: [ZJOI2007]报表统计
- React数据流和组件间的通信总结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android语音声波控件 Android条形波控件
- Ubuntu下安装CUDA10.0以及问题
- Android ListView实现单选及多选等功能示例
- Recyclerview添加头布局和尾布局、item点击事件详解
- Android 中LayoutInflater.inflate()方法的介绍
- Android ListView实现简单列表功能
- Ubuntu16.04上安装CUDA9.0 详细教程
- Android使用LinearLayout设置边框
- Android编程实现状态保存的方法分析
- Android中TextView和ImageView实现倾斜效果
- Notification消息通知 自定义消息通知内容布局
- Android编程实现带渐变效果的圆角矩形示例
- Android仿苹果关机界面实现代码
- Android使用RecycleView实现拖拽交换item位置
- Android编程之计时器Chronometer简单示例