SICK激光雷达LMS511测量数据说明
帧结构说明
LMS511的官方手册存在几个版本,在《Laser Measurement Systems of the LMS500 Product Family》的英文手册中,对单次(连续)获取测量结果的返回帧结构的说明中,容易误导用户(也可能是我没注意到细节)。
例如,对单次返回的帧结构,手册上是这样描述的。
单次获取对应的十六进制命令为:
02 73 52 4E 20 4C 4D 44 73 63 61 6E 64 61 74 61 20 31 03
接收数据的命令格式:
sRA LMDscandata VersionNumber DeviceNumber SerialNumber DeviceStatus MessageCounter ScanCounter PowerUpDuration TransmissionDuration InputStatus OutputStatus ReservedByteA ScanningFrequency MeasurementFrequency NumberEncoders [EncoderPosition EncoderSpeed] NumberChannels16Bit [MeasuredDataContent ScalingFactor ScalingOffset StartingAngle AngularStepWidth NumberData [Data_1 Data_n]] NumberChannels8Bit [MeasuredDataContent ScalingFactor ScalingOffset StartingAngle AngularStepWidth [NumberData Data_1 Data_n] Position [XPosition YPosition ZPosition XRotation YRotation ZRotation RotationType] Name [DeviceName] Comment [CommentContent] TimeInfo [Year Month Day Hour Minute Second Microseconds] EventInfo [EventType EncoderPosition EventTime AngularPosition]
在该手册中对VersionNumber DeviceNumber等数据的描述如下:
在length(byte)一列中,对不同参数的字节数做了说明,VersionNumber为2个字节。通过对比帧结构说明和实际获取的数据中发现,VersionNumber只有1个字节,并且后面其他参数也有类似的情况出现。所以这个字节数是否代表参数最大占有字节数。
在一个版本的中文手册《LMS5XX 中文操作手册》的最后一页发现这样的描述:
通过对比这份说明和实际的数据,则能很好的对应,所以以这份说明的帧结构为参考依据。
数据举例
帧结构中,每个字段之间是空格(20)分开的。值得注意的是,LMS511输出数据均是字符的ASCII码,需要将其转化为十六进制的字符,再转为十进制。输出的测量数据,有的是3个字节,有的是2个字节,甚至1个字节,所以只能以空格来作为划分依据。
以下是读取原始数据文本,并绘制二维扫描图的matlab程序。
clear all
clc
angle_orign_temp = [];
angle_step_temp = [];
data_length_temp = [];
data_range_temp =[];
data_range = [];
file_addr = 'data.txt';
data = textread(file_addr,'%s')'; %以字符串的形式读取原始数据
data_orign_dec = hex2dec(data)';
flag = [48,48,48,48,48,48,48,48]; %原始帧结构中的预留标志段,8个0,十进制
flag_postion = findstr(data_orign_dec,flag ); %寻找标志段所在位置
data_orign_use = data_orign_dec(flag_postion+8:end);
%LMS511以空格来区分不同字段,每个字段有各自的含义,只取有用部分
spc_location = find(data_orign_use == 32); %找出空格字符所在的下标
%提取起始角度
for i1 = spc_location(1)+1: spc_location(2)-1
angle_orign_temp = strcat(angle_orign_temp,char(data_orign_use(i1)));
end
angle_orign = hex2dec(angle_orign_temp);
angle_orign = (angle_orign/10000)*pi/180;
%提取角度分辨率
for i2 = spc_location(2)+1: spc_location(3)-1
angle_step_temp = strcat(angle_step_temp,char(data_orign_use(i2)));
end
angle_step = hex2dec(angle_step_temp);
angle_step = (angle_step/10000)*pi/180;
%提取测量点数
for i3 = spc_location(3)+1: spc_location(4)-1
data_length_temp = strcat(data_length_temp,char(data_orign_use(i3)));
end
data_length = hex2dec(data_length_temp);
data_polar =zeros(2,data_length);
data_rec =zeros(2,data_length);
%将数据转换成有效的十进制数
for i = 1:data_length
for j = spc_location(i+3)+1:spc_location(i+4)-1
data_range_temp = strcat(data_range_temp,char(data_orign_use(j)));
end
data_range(i) = hex2dec(data_range_temp);
data_range_temp = [];
end
for w = 1:data_length
if w == 1
data_polar(1,w) = angle_orign;
data_polar(2,w) = data_range(w);
else
data_polar(1,w) = data_polar(1,w-1) + angle_step;
data_polar(2,w) = data_range(w);
end
end
%极坐标到直角坐标变换
for x = 1:data_length
data_rec(1,x) = cos(data_polar(1,x))*data_polar(2,x);
data_rec(2,x) = sin(data_polar(1,x))*data_polar(2,x);
end
plot(data_rec(1,:),data_rec(2,:),'.')
注意事项
matlab代码有两点需要注意:
- 原始数据的文本格式。我的数据文本文件中每个数据以空格为分割,不含有其他字符。
- 我的初始角度没考虑负角度,因为工作限定,角度都非负,所以有负角度的情况需要微调(原始数据会以补码形式给出)。
%修正部分代码,如果起始角度为负数的话,增加一个判断
%提取起始角度
for i1 = spc_location(1)+1: spc_location(2)-1
angle_orign_temp = strcat(angle_orign_temp,char(data_orign_use(i1)));
end
if(angle_orign_temp(1) == 'F')
angle_orign = hex2dec(angle_orign_temp) - 2^32; %起始角度为负,用8位十六进制表示,最高位为F
angle_orign = (angle_orign/10000)*pi/180;
else
angle_orign = hex2dec(angle_orign_temp);
angle_orign = (angle_orign/10000)*pi/180;
end
%提取角度分辨率
后续程序改进
有网友问,这段程序可不可以用来打开SICK官方软件SOPAS保存下来的log数据文件,答案是不可以!,因为数据里面穿插有<>字符。实际上只要先去掉<>,则剩下的就可以直接使用上述代码。
算了好人做到底,直接给可用于读取log文件数据的MATLAB代码,如下:
clear all
clc
angle_orign_temp = [];
angle_step_temp = [];
data_length_temp = [];
data_range_temp =[];
data_range = [];
data_orign = importdata('data.log');
[row,col]=size(data_orign);
for i_frame = 1:row
data_orign_temp1 = strcat(data_orign{i_frame,1}); %把读到的按行存的cell格式转换成字符串
header_pos = findstr(data_orign_temp1,'<02>');
data_orign_temp11= data_orign_temp1(header_pos:end);
data_orign_temp11(find(data_orign_temp11 == '<')) = []; %去掉字符串中的空格
data_orign_temp2 = strrep(data_orign_temp11,'>',' '); %用空格替换>
data_orign_temp3 = regexp(data_orign_temp2, ' ', 'split'); %按空格将string分割成数组
data_orign_dec = hex2dec(data_orign_temp3)'; %进制转换
flag = [48,48,48,48,48,48,48,48]; %原始帧结构中的预留标志段,8个0,十进制
flag_postion = findstr(data_orign_dec,flag ); %寻找标志段所在位置
data_orign_use = data_orign_dec(flag_postion+8:end);
%LMS511以空格来区分不同字段,每个字段有各自的含义,只取有用部分
spc_location = find(data_orign_use == 32); %找出空格字符所在的下标
%提取起始角度
for i1 = spc_location(1)+1: spc_location(2)-1
angle_orign_temp = strcat(angle_orign_temp,char(data_orign_use(i1)));
end
if(angle_orign_temp(1) == 'F')
angle_orign = hex2dec(angle_orign_temp) - 2^32; %起始角度未负的话,用8位十六进制表示,最高位为F
angle_orign = (angle_orign/10000)*pi/180;
else
angle_orign = hex2dec(angle_orign_temp);
angle_orign = (angle_orign/10000)*pi/180;
end
%提取角度分辨率
for i2 = spc_location(2)+1: spc_location(3)-1
angle_step_temp = strcat(angle_step_temp,char(data_orign_use(i2)));
end
angle_step = hex2dec(angle_step_temp);
angle_step = (angle_step/10000)*pi/180;
%提取测量点数
for i3 = spc_location(3)+1: spc_location(4)-1
data_length_temp = strcat(data_length_temp,char(data_orign_use(i3)));
end
data_length = hex2dec(data_length_temp);
data_polar =zeros(2,data_length);
data_rec =zeros(2,data_length);
%将数据转换成有效的十进制数
for i = 1:data_length
for j = spc_location(i+3)+1:spc_location(i+4)-1
data_range_temp = strcat(data_range_temp,char(data_orign_use(j)));
end
data_range(i) = hex2dec(data_range_temp);
data_range_temp = [];
end
i = 1;
for w = 1:data_length
if w == 1
data_polar(1,w) = angle_orign;
data_polar(2,w) = data_range(w);
else
data_polar(1,w) = data_polar(1,w-1) + angle_step;
data_polar(2,w) = data_range(w);
end
end
%极坐标到直角坐标变换
for x = 1:data_length
data_rec(1,x) = cos(data_polar(1,x))*data_polar(2,x);
data_rec(2,x) = sin(data_polar(1,x))*data_polar(2,x);
end
% figure
% plot(data_polar(1,:),data_polar(2,:),'.')
plot(data_rec(1,:),data_rec(2,:),'.')
angle_orign_temp = [];
angle_step_temp = [];
data_length_temp = [];
data_range_temp =[];
data_range = [];
pause(1);
end
SICK激光雷达LMS511测量数据说明的更多相关文章
- SICK激光扫描仪LMS511连接通讯
一.设备介绍: 型号:LMS511-10100(DC 24v) 品牌:SICK 操作环境:Windows 10 64bit 软件:SOPAS ET 连接线:串口转网口线(1根/4针 子头),电源线( ...
- SICK LMS111激光雷达的使用
LMS111系列是SICK推出的一款用于室外区域防撞.测量及安防的激光扫描器.LMS111同西克其他扫描器一样,采用成熟的ToF原理,非接触式检测,且加入了最新的多次回波检测技术(两次回波),使得LM ...
- SICK TiM561激光雷达的使用
TIM系列激光扫描传感器原理: 激光发射器发出激光脉冲,当激光碰到物体后,部分激光反射回激光接收器.通过计算发射/接收脉冲时间差,可以计算出距离值.激光扫描器连续不停的发射激光脉冲,由旋转的光学机构将 ...
- VREP中的二维激光雷达
目前,轮式机器人的研究中已经大量使用激光雷达辅助机器人的避障导航,考虑到使用成本,一般二维激光雷达使用较多,如下图.由于只能扫描一个平面,如果想用二维激光雷达获取环境三维点云,则需要通过移动机器人或加 ...
- 使用XV-11激光雷达做hector_slam
大家在学习ROS中不可避免需要使用激光雷达,高精地图.实时定位以及障碍物检测等多项技术,而这些技术都离不开光学雷达的支持,但是呢雷达这真是太贵了,大部分人是负担不起(实验室.研究所土豪可以略过),但是 ...
- golang+webgl实践激光雷达(一)激光扫描仪基础知识
一.前言 最近做一个测量料堆形状的项目,通过前期调研,最后决定用激光测距原理进行测量.通过旋转云台+激光扫描仪实现空间三维坐标的测量.其中激光扫描仪扫射的是一个二维的扫描面,再通过云台旋转,则形成一个 ...
- Lidar激光雷达市场
Lidar激光雷达市场 近年来,激光雷达技术在飞速发展,从一开始的激光测距技术,逐步发展了激光测速.激光扫描成像.激光多普勒成像等技术,如今在无人驾驶.AGV.机器人等领域已相继出现激光雷达的身影. ...
- SLAM+语音机器人DIY系列:(三)感知与大脑——1.ydlidar-x4激光雷达
摘要 在我的想象中机器人首先应该能自由的走来走去,然后应该能流利的与主人对话.朝着这个理想,我准备设计一个能自由行走,并且可以与人语音对话的机器人.实现的关键是让机器人能通过传感器感知周围环境,并通过 ...
- matlab 三维激光雷达点云的地面与障碍物检测
基于激光雷达的地面与障碍物检测 这个例子告诉我们如何去检测地平面并且找到三维LIDAR数据中与车相近的障碍物. 这个过程能够方便我们对汽车导航的可行驶区域规划. 注:每一帧的雷达属于都被存储为三维的雷 ...
随机推荐
- 浅谈Java多态
什么是Java中的多态?又是一个纸老虎的概念,老套路,把它具体化,细分化,先想三个问题(注意,这里不是简单的化整为零,而是要建立在学习一个新概念时的思考框架): 1.这个东西有什么用?用来干什么的?它 ...
- 从零开始搭建框架SSM+Redis+Mysql(一)之摘要
从零开始搭建框架SSM+Redis+Mysql(一)之摘要 本文章为本人实际的操作后的回忆笔记,如果有步骤错漏,希望来信307793969@qq.com或者评论指出. 本文章只体现过程,仅体现操作流程 ...
- python3中判断字串类型
s为字串 s.isalnum() #所有字符都是数字或者字母,为真返回 Ture,否则返回 False. s.isalpha() #所有字符都是字母,为真返回 Ture,否则返回 False. s.i ...
- linux下svn的安装与配置
---恢复内容开始--- linux下svn的安装与配置 Linux发行版本:CentOS6.5 1.安装subversion sudo yum -y install subversion 2.创建s ...
- [Python] 文科生零基础学编程系列三——数据运算符的基本类别
上一篇:[Python] 文科生零基础学编程系列二--数据类型.变量.常量的基础概念 下一篇: ※ 程序的执行过程,就是对数据进行运算的过程. 不同的数据类型,可以进行不同的运算, 按照数据运算类型的 ...
- 如何在openlayer接入矢量数据
先说矢量数据集接入,我们通过GeoJSON的示例代码(http://openlayers.org/en/latest/examples/geojson.html)了解Openlayers的源代码,确定 ...
- 从架构演进的角度聊聊Spring Cloud都做了些什么?
Spring Cloud作为一套微服务治理的框架,几乎考虑到了微服务治理的方方面面,之前也写过一些关于Spring Cloud文章,主要偏重各组件的使用,本次分享主要解答这两个问题:Spring Cl ...
- [转]Java - 集合框架完全解析
数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵 ...
- sed命令详解 vim高级技巧 shell编程上
第1章 sed命令详解 1.1 查找固定的某一行 1.1.1 awk命令方法 [root@znix ~]# awk '!/oldboy/' person.txt 102,zhangyao,CTO 10 ...
- 【转载】SQL注入
"SQL注入"是一种利用未过滤/未审核用户输入的攻击方法("缓存溢出"和这个不同),意思就是让应用运行本不应该运行的SQL代码.如果应用毫无防 ...