一种基于十字交叉线的用于三维重建的激光雷达制作——000任务计划
制作说明
本次制作花费的总时长为 11月15至12月31号 ,主要分为三个部分:1、硬件部分的调试;2、软件部分开发;3、功能算法的优化。>。<。
01、功能说明
主要是对一年级及二年级上半年所学的相关知识进行一次详细的总结和完善:
- 激光三角法 ,虽然有些落后,但值得回顾;
- 相机坐标系的转换,包括 相机坐标系、像素坐标系、世界坐标系、图像坐标系 进行说明与推导;
- 激光点的多种提取方法 包括Steger、Hessian、极值法、自适应阈值法以及质心法,另外算法部分将要进行多种提取方法的融合以得到最佳结果 ;
- 包括 MATLAB串口通讯方式 的介绍;
- 微处理器使用MSP4301 进行通讯与控制;
- 包括 舵机调试 功能2;
- 介绍 微处理器与PC端的串口通信 ;
- 拟增加 OpenCV 软件开发。
02、相关配件介绍
I.舵机
- 舵机外形及旋转角度、内部结构示意
- 舵机控制原理:
- 舵机相关参数
- 使用介绍
激光器
- 购买的激光参数介绍
USB摄像头
串口显示屏
MSP430
继电器
03、3D激光雷达简介3
三维重建技术根据是否需要光源主动照射分为被动视觉和主动视觉。被动视觉主要指双目视觉,模拟人眼视觉;主动视觉主要指单目视觉,其主要包括结构光和编码光三维检测技术,由专门的光源照射物体,光源完成对整个被测物体的扫描以得到被测物体表面的轮廓信息。单目视觉常利用一台摄像机及一个结构光光源完成对物体的检测,避免了双目视觉检测中存在的摄像机间最优距离及特征点匹配的问题。常用的单目视觉系统又称为结构光三维重建系统,其在工业生产、生物医疗、食品监测和文物保护等领域得以实践及应用。
04、亚像素级激光线条中心点提取方法简介
在结构光的三维检测过程中,因实际投射光平面具有一定的厚度,使得拍摄得到的激光交线具有一定宽度,理想情况下我们往往将能量最大亮度最高的中心线视为光条的中心,但是实际中图像拍摄得到的光条中心区域往往呈现饱和状态,因此需要结合其他算法进行提取。如何实现光条中心快速提取不但决定了检测的效率更决定了检测的精度。目前常用的光条中心提取方法主要分为两大类,即基于形态特征的光条中心提取方法和基于灰度特征的光条中心提取方法。前者包括边缘法、几何中心法、细化法,后者主要包括极值法、灰度重心法、方向模板法、高斯拟合法、Hessian 矩阵法。20181125
05、结构光三维重建基本原理简介
结构光立体视觉方法是使用标准的光栅条纹结构光投射到物体表面,投影光条跟随物体表面形状的起伏而发生变化,摄像机拍摄物体表面图像,从被物体表面形状所调制了的条纹模式中,提取出物体的三维信息。结构光立体视觉方法以光学三角法测量理论为基础,在测量之前先要对摄像机和光学投影仪标定。4
06、激光三角法简介
三角法的原理如下图所示,激光器发射激光,在照射到物体后,反射光由线性CCD接收,由于激光器和探测器间隔了一段距离,所以依照光学路径,不同距离的物体将会成像在CCD上不同的位置。按照三角公式进行计算,就能推导出被测物体的距离。
07、相机标定简介
在结构光检测技术中,要将摄像机获取的二维图像信息转换为空间环境中的三维位置信息,首先需通过摄像机参数标定构建摄像机成像的几何模型,即摄像机的内、外参数;其次建立图像与空间对应点之间的相互关系,即标定激光平面方程;最后需要获得物体相对于扫描系统的运动方向,以便对整个被测物体实现三维重建。
08、PWM控制舵机
51控制舵机实例,理解起来很快
//#include <STC15.h>
//#include"STC89C5xRC.H"
//一定要用12M的晶振
//一定要用12M的晶振
//一定要用12M的晶振
//一定要用12M的晶振
//一定要用12M的晶振
//一定要用12M的晶振
#include "reg51.h"
#define uint8 unsigned char
#define uint16 unsigned short int
#define uint32 unsigned long
sbit SERVO0=P0^0; //控制舵机的PWM输出口
uint16 Servo0PwmDuty=1500; //PWM脉冲宽度
/***********************************************************
* 名 称: DelayMs(uint16 ms)
* 功 能: 延时ms毫秒
* 入口参数: ms 毫秒
* 出口参数: 无
* 说 明:
/**********************************************************/
void DelayMs(uint16 ms)
{
uint16 i,j;
for(i=0;i<85;i++) //89单片机用85,12系列单片机用800
for(j=0;j<ms;j++);
}
/***********************************************************
* 名 称:InitTimer0()
* 功 能:时钟0初始化
* 入口参数:无
* 出口参数:无
* 说 明:12M晶振,12分频,所以计数器每递增一个数就是1微秒,完全满足舵机控制的精度要求
因为定时器是TH0,TL0都要全部计数到0xFF后在计1个数就会产生中断,所以要想产生
x毫秒的中断,那么TH0,TL0就应该赋值(0xFFFF-x) 从这个值开始计数产生定时中断
/**********************************************************/
void InitTimer0(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x00; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //开定时器0中断
}
/***********************************************************
* 名 称:Timer0Value(uint16 pwm)
* 功 能:给定时器0计数器赋值产生定时中断
* 入口参数:pwm 控制舵机的PWM脉冲宽度值(范围:500~2500)
* 出口参数:无
* 说 明:12M晶振,12分频,所以计数器每递增一个数就是1微秒,完全满足舵机控制的精度要求
因为定时器是TH0,TL0都要全部计数到0xFF后在计1个数就会产生中断,所以要想产生
pwm毫秒的中断,那么TH0,TL0就应该赋值(0xFFFF-pwm) 从这个值开始计数产生定时中断
/**********************************************************/
void Timer0Value(uint16 pwm)
{
uint16 value;
value=0xffff-pwm;
TR0 = 0;
TL0=value; //16位数据给8位数据赋值默认将16位数据的低八位直接赋给八位数据
TH0=value>>8; //将16位数据右移8位,也就是将高8位移到低八位,再赋值给8位数据
TR0 = 1;
}
/***********************************************************
* 名 称: main()
* 功 能: 入口函数
* 入口参数: 无
* 出口参数: 无
* 说 明:
/**********************************************************/
void main(void)
{
InitTimer0(); //定时器0初始化
EA = 1; //开总中断
while(1) //大循环
{
Servo0PwmDuty = 500; //脉冲宽度在500微秒,对应-90°
DelayMs(1000); //延时1秒
Servo0PwmDuty = 1000; //脉冲宽度在1000微秒,对应-45°
DelayMs(1000);
Servo0PwmDuty = 1500;
DelayMs(1000);
Servo0PwmDuty = 2000;
DelayMs(1000);
Servo0PwmDuty = 2500;
DelayMs(1000);
Servo0PwmDuty = 2000;
DelayMs(1000);
Servo0PwmDuty = 1500;
DelayMs(1000);
Servo0PwmDuty = 1000;
DelayMs(1000);
}
}
/***********************************************************
* 名 称: Timer0_isr() interrupt 1 using 1
* 功 能: 时钟0中断处理
* 入口参数: 无
* 出口参数: 无
* 说 明:
/**********************************************************/
void Timer0_isr(void) interrupt 1 using 1
{
static uint16 i = 1; //静态变量:每次调用函数时保持上一次所赋的值,
//跟全局变量类似,不同是它只能用于此函数内部
switch(i)
{
case 1:
SERVO0 = 1; //PWM控制脚高电平
//给定时器0赋值,计数Pwm0Duty个脉冲后产生中断,下次中断会进入下一个case语句
Timer0Value(Servo0PwmDuty);
break;
case 2:
SERVO0 = 0; //PWM控制脚低电平
//高脉冲结束后剩下的时间(20000-Pwm0Duty)全是低电平了,Pwm0Duty + (20000-Pwm0Duty) = 20000个脉冲正好为一个周期20毫秒
Timer0Value(20000-Servo0PwmDuty);
i = 0;
break;
}
i++;
}