• 基于fpga的单线激光雷达数据处理


    激光雷达:

    首先来给大家稍微介绍以下激光雷达,激光雷达,即Light Detation and ranging,它相比于其他雷达,优点非常明确,包括 1)、具有极高的分辨率;

    2)、抗干扰能力强;

    3)、获取的信息量丰富;

    4)、全天时工作;

    最近一段时间有幸接触到镭神LS01C型单线激光雷达,LS01C型激光雷达是深圳市镭神智能系统公司研发的一款低成本二维扫描测距产品。该激光雷达可实现6米范围内的360°二维平面扫描,产生空间的平面点云地图用于地图绘制、机器人自主定位导航、智能设备壁障等应用。

    激光测距采用激光三角测距系统,三角测距原理可参考

    http://blog.csdn.net/xiangz_csdn/article/details/53814290

    LSLIDAR通讯参数:

    波特率:230400bps;

    校验位:NONE;

    数据位:8bits;

    停止位:1bits;

    数据格式:十六进制。

    首先接触雷达,我从数据通信入手,通过uart串口发送启动指令(0xA5 0x2C 0xE1 0xAA 0xBB 0xCC 0xDD
    )和停止指令(0xA5 0x25 0xE1 0xAA 0xBB 0xCC 0xDD
    )来控制雷达运行和停止。采用两种方法来控制雷达运行状态:(1)、将启动和停止指令预存在程序中,然后和FPGA板子的开关相结合,通过开关来控制雷达;

    (2)、采用串口助手来发送指令控制雷达运行和停止。

    接下来贡上两种程序代码:

    一、预存指令:

      分为四个模块:分频模块clkdiv.v、发送模块uarttx.v、测试模块(存指令模块)test_tx_r.v、顶层模块top_tx_r.v

    module clkdiv(clk, clkout); //分频模块
    input clk;  
            
    output clkout;  
        
     reg clkout; 
    reg [15:0] cnt;
    always @(posedge clk) 
      
    begin //板子时钟为100MHZ,采用16倍波特率进行采样,计算得分频系数为27
    if(cnt == 16'd13)
    begin  
    clkout <= 1'b1; 
    cnt <= cnt + 16'd1; 
    end  
    else if(cnt == 16'd27) 
    begin  
    clkout <= 1'b0; 
    cnt <= 16'd0; 
    end 
    else 
    begin  
    cnt <= cnt + 16'd1; 
    end 
    end 
    endmodule
    module uarttx(clk, datain, wrsig, idle, tx);//发送模块
    input clk;  
        
      
    input [7:0] datain;   //并行输入8位数据
    input wrsig;   //输入控制位,上升沿有效
    output idle;//输出标志位
    output tx;  //串行输出数据
     
    reg idle, tx; 
    reg send;  
    reg wrsigbuf, wrsigrise; 
    reg presult;  //发送校验
    reg[7:0] cnt;   
     
    parameter paritymode = 1'b0; 
    
    always @(posedge clk) //判断wrsig的上升沿
    begin  
    wrsigbuf <= wrsig;  
    wrsigrise <= (~wrsigbuf) & wrsig; 
    end  
    always @(posedge clk) 
    begin  
    if (wrsigrise && (~idle)) //wrsig为上升沿且处于空闲状态发送数据
     
    begin  
    send <= 1'b1; //进行发送
    end  
    else if(cnt == 8'd152) //8位数据发送完毕
    
    begin  
    send <= 1'b0; 
    end 
    end  
    always @(posedge clk) 
    begin  
    if(send == 1'b1) 
    begin  
    case(cnt)   
        
    8'd0: //发送起始位
    begin  
    tx <= 1'b0; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd16: //发送第一位
    begin  
    tx <= datain[0];  
      
    presult <= datain[0]^paritymode; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd32: //发送第二位
    begin  
    tx <= datain[1]; 
    presult <= datain[1]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd48: //发送第三位
    begin  
    tx <= datain[2];  
    presult <= datain[2]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd64: //发送第四位
    begin  
    tx <= datain[3]; 
    presult <= datain[3]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd80: //发送第五位
    begin  
    tx <= datain[4];  
    
    presult <= datain[4]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd96: //发送第六位
    begin  
    tx <= datain[5];  
    
    presult <= datain[5]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd112: //发送第七位
    begin  
    tx <= datain[6]; 
    
    presult <= datain[6]^presult; 
    idle <= 1'b1;  //处于忙状态 
    cnt <= cnt + 8'd1; 
    end 
    8'd128: //发送第八位
    begin  
    tx <= datain[7]; 
    presult <= datain[7]^presult;  
    
    idle <= 1'b1;  //处于忙状态 
    cnt <= cnt + 8'd1; 
    end 
    8'd144: //发送停止位
    begin  
    tx <= 1'b1;  
    idle <= 1'b1;  //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd152: 
    begin  
    tx <= 1'b1; 
    idle <= 1'b0;// 处于空闲状态,可以发数据
    cnt <= cnt + 8'd1; 
    end 
    default: 
    begin  
    cnt <= cnt + 8'd1; 
    end 
    endcase 
    end 
    else 
    begin  
    tx <= 1'b1; 
    cnt <= 8'd0; 
    idle <= 1'b0; 
    end 
    end  
    endmodule 
    module testuart(clk, dataout,wrsig,rst,key_mov,key_stop); 
    input clk,rst; 
    input key_mov;//开始开关
    input key_stop;//停止开关
    output[7:0] dataout; 
    output wrsig;  //发送指令标志位
    reg [7:0] dataout; 
    reg wrsig; 
    reg [16:0] cnt; 
    
    
    always @(posedge clk or negedge rst ) 
    begin
      if(!rst)begin
        dataout<= 0;
        cnt <=0;
        end
    else 
    begin
    if(key_mov==1'b1)//运行开关闭合有效
      begin
         if(cnt <= 1779) //一组指令周期数
            begin  //发送开始指令
              case(cnt)
              16'd254: begin
                       dataout <= 8'hA5;wrsig <= 1'b1;  cnt <= cnt + 16'd1;end
              16'd508:  begin
                       dataout <= 8'h2C;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
              16'd762: begin
                       dataout <= 8'hE1;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
              16'd1016: begin
                       dataout <= 8'hAA;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
              16'd1270:  begin
                       dataout <= 8'hBB;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
               16'd1524: begin
                       dataout <= 8'hCC;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
              16'd1778: begin
                       dataout <= 8'hDD;wrsig <= 1'b1;  cnt <= cnt + 16'd1;end
                
               default:begin
                      wrsig <= 1'b0;  
                     cnt <= cnt + 16'd1;end
              endcase
            end
          else 
             begin  
              wrsig <= 1'b0; 
              cnt <= 16'd0;  
             end 
         end
    else  if(key_stop==1'b1)//停止开关闭合
        begin 
         if(cnt <= 1779) 
            begin  //发送停止指令
              case(cnt)
                16'd254: begin
                           dataout <= 8'hA5;wrsig <= 1'b1;  cnt <= cnt + 16'd1;end
                16'd508:  begin
                          dataout <= 8'h25;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
                16'd762: begin
                        dataout <= 8'hE1;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
                16'd1016: begin
                        dataout <= 8'hAA;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
                16'd1270:  begin
                         dataout <= 8'hBB;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
                16'd1524: begin
                         dataout <= 8'hCC;wrsig <= 1'b1; cnt <= cnt + 16'd1; end
                 16'd1778: begin
                         dataout <= 8'hDD;wrsig <= 1'b1;  cnt <= cnt + 16'd1;end
                
                default:begin
                       wrsig <= 1'b0;  
                      cnt <= cnt + 16'd1;end
              endcase
            end
         else 
            begin  
              wrsig <= 1'b0; 
              cnt <= 16'd0;  
            end 
        end
    else
            begin  
              wrsig <= 1'b0; 
              cnt <= 16'd0;  
            end 
    end
    end
    endmodule  
    module uarttx(clk, datain, wrsig, idle, tx);//发送模块
    input clk;  
        
      
    input [7:0] datain;   //并行输入8位数据
    input wrsig;   //输入控制位,上升沿有效
    output idle;//输出标志位
    output tx;  //串行输出数据
     
    reg idle, tx; 
    reg send;  
    reg wrsigbuf, wrsigrise; 
    reg presult;  //发送校验
    reg[7:0] cnt;   
     
    parameter paritymode = 1'b0; 
    
    always @(posedge clk) //判断wrsig的上升沿
    begin  
    wrsigbuf <= wrsig;  
    wrsigrise <= (~wrsigbuf) & wrsig; 
    end  
    always @(posedge clk) 
    begin  
    if (wrsigrise && (~idle)) //wrsig为上升沿且处于空闲状态发送数据
     
    begin  
    send <= 1'b1; //进行发送
    end  
    else if(cnt == 8'd152) //8位数据发送完毕
    
    begin  
    send <= 1'b0; 
    end 
    end  
    always @(posedge clk) 
    begin  
    if(send == 1'b1) 
    begin  
    case(cnt)   
        
    8'd0: //发送起始位
    begin  
    tx <= 1'b0; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd16: //发送第一位
    begin  
    tx <= datain[0];  
      
    presult <= datain[0]^paritymode; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd32: //发送第二位
    begin  
    tx <= datain[1]; 
    presult <= datain[1]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd48: //发送第三位
    begin  
    tx <= datain[2];  
    presult <= datain[2]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd64: //发送第四位
    begin  
    tx <= datain[3]; 
    presult <= datain[3]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd80: //发送第五位
    begin  
    tx <= datain[4];  
    
    presult <= datain[4]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd96: //发送第六位
    begin  
    tx <= datain[5];  
    
    presult <= datain[5]^presult; 
    idle <= 1'b1;   //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd112: //发送第七位
    begin  
    tx <= datain[6]; 
    
    presult <= datain[6]^presult; 
    idle <= 1'b1;  //处于忙状态 
    cnt <= cnt + 8'd1; 
    end 
    8'd128: //发送第八位
    begin  
    tx <= datain[7]; 
    presult <= datain[7]^presult;  
    
    idle <= 1'b1;  //处于忙状态 
    cnt <= cnt + 8'd1; 
    end 
    8'd144: //发送停止位
    begin  
    tx <= 1'b1;  
    idle <= 1'b1;  //处于忙状态
    cnt <= cnt + 8'd1; 
    end 
    8'd152: 
    begin  
    tx <= 1'b1; 
    idle <= 1'b0;// 处于空闲状态,可以发数据
    cnt <= cnt + 8'd1; 
    end 
    default: 
    begin  
    cnt <= cnt + 8'd1; 
    end 
    endcase 
    end 
    else 
    begin  
    tx <= 1'b1; 
    cnt <= 8'd0; 
    idle <= 1'b0; 
    end 
    end  
    endmodule 

    二、通过串口助手来发送:

          分频模块和上面的一样,此处不再呈上;

    module top(clk,rx,tx,idle);
    input clk,rx;
    output tx,idle;
    
    wire tx,idle;
    wire clkout,rdsig;
    wire [7:0] dataout;
    
     clkdiv clkdiv_inst(
     .clk(clk),
     .clkout(clkout)
      );
     
     uarttx uarttx_inst(
       .clk(clkout), 
       .datain(dataout), 
       .wrsig(rdsig), 
       .idle(idle), 
       .tx(tx)
       );
      
      uartrx uartrx_inst(
      .clk(clkout), 
      .rx(rx), 
      .dataout(dataout), 
      .rdsig(rdsig)
      );
      endmodule
    module uartrx(clk, rx, dataout, rdsig);
    input clk; //采样时钟
    input rx; //UART 数据输入
    output dataout; //接收数据输出
    output rdsig;
    reg[7:0] dataout;
    reg rdsig;
    reg [7:0] cnt;
    reg rxbuf, rxfall, receive;
    parameter paritymode = 1'b0;
    reg presult, idle;
    always @(posedge clk) //检测线路的下降沿
    begin
    rxbuf <= rx;
    rxfall <= rxbuf & (~rx);
    end
    always @(posedge clk)
    begin
    if (rxfall && (~idle)) //检测到线路的下降沿并且原先线路为空闲,启动接收数据进程
    begin
    receive <= 1'b1;
    end
    else if(cnt == 8'd152) //接收数据完成
    begin
    receive <= 1'b0;
    end
    end
    always @(posedge clk)
    begin
    if(receive == 1'b1)
    begin
    case (cnt)
    8'd0:
    begin
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd24: //接收第 0 位数据
    begin
    idle <= 1'b1;
    dataout[0] <= rx;
    presult <= paritymode^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd40: //接收第 1 位数据
    begin
    idle <= 1'b1;
    dataout[1] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd56: //接收第 2 位数据
    begin
    idle <= 1'b1;
    dataout[2] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd72: //接收第 3 位数据
    begin
    idle <= 1'b1;
    dataout[3] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd88: //接收第 4 位数据
    begin
    idle <= 1'b1;
    dataout[4] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd104: //接收第 5 位数据
    begin
    idle <= 1'b1;
    dataout[5] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd120: //接收第 6 位数据
    begin
    idle <= 1'b1;
    dataout[6] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd136: //接收第 7 位数据
    begin
    idle <= 1'b1;
    dataout[7] <= rx;
    presult <= presult^rx;
    cnt <= cnt + 8'd1;
    rdsig <= 1'b0;
    end
    8'd144:
    begin
    idle <= 1'b1;
    cnt <= cnt + 1'b1;
    rdsig <= 1'b1;
    end
    default:
    begin
    cnt <= cnt + 8'd1;
    end
    endcase
    end
    else
    begin
    cnt <= 8'd0;
    idle <= 1'b0;
    rdsig <= 1'b0;
    end
    end
    endmodule
    module uarttx(clk, datain, wrsig, idle, tx);
    input clk; //UART 时钟
    input [7:0] datain; //需要发送的数据
    input wrsig; //发送命令,上升沿有效
    output idle; //线路状态指示,高为线路忙,低为线路空闲
    output tx; //发送数据信号
    reg idle, tx;
    reg send;
    reg wrsigbuf, wrsigrise;
    reg presult;
    reg[7:0] cnt; //计数器
    parameter paritymode = 1'b0;
    //检测发送命令是否有效
    always @(posedge clk)
    begin
    wrsigbuf <= wrsig;
    wrsigrise <= (~wrsigbuf) & wrsig;
    end
    always @(posedge clk)
    begin
    if (wrsigrise && (~idle)) //当发送命令有效且线路为空闲时,启动新的数据发送进程
    begin
    send <= 1'b1;
    end
    else if(cnt == 8'd152) //一帧资料发送结束
    begin
    send <= 1'b0;
    end
    end
    always @(posedge clk)
    begin
    if(send == 1'b1)
    begin
    case(cnt) //产生起始位
    8'd0:
    begin
    tx <= 1'b0;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd16:
    begin
    tx <= datain[0]; //发送数据 0 位
    presult <= datain[0]^paritymode;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd32:
    begin
    tx <= datain[1]; //发送数据 1 位
    presult <= datain[1]^presult;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd48:
    begin
    tx <= datain[2]; //发送数据 2 位
    presult <= datain[2]^presult;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd64:
    begin
    tx <= datain[3]; //发送数据 3 位
    presult <= datain[3]^presult;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd80:
    begin
    tx <= datain[4]; //发送数据 4 位
    presult <= datain[4]^presult;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd96:
    begin
    tx <= datain[5]; //发送数据 5 位
    presult <= datain[5]^presult;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd112:
    begin
    tx <= datain[6]; //发送数据 6 位
    presult <= datain[6]^presult;
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd128:
    begin
    tx <= datain[7]; //发送数据 7 位
    presult <= datain[7]^presult;
    idle <= 1'b1;
    cnt <= cnt + 10'd1;
    end
    8'd144:
    begin
    tx <= 1'b1; //发送停止位
    idle <= 1'b1;
    cnt <= cnt + 8'd1;
    end
    8'd152:
    begin
    tx <= 1'b1;
    idle <= 1'b0; //一帧资料发送结束
    cnt <= cnt + 8'd1;
    end
    default:
    begin
    cnt <= cnt + 8'd1;
    end
    endcase
    end
    else
    begin
    tx <= 1'b1;
    cnt <= 8'd0;
    idle <= 1'b0;
    end
    end
    endmodule

    串口通信是熟悉板子的入门练习,可以深刻理解发送数据的方式,以及波特率的含义和计算。

  • 相关阅读:
    资产采集:
    思想:
    Redis 以及 Python操作Redis
    Django在使用Mysql迁移数据库时,会报的错
    HTML
    数据库操作(四)
    数据库操作(二)
    数据库操作(三)
    数据库操作(一)
    MySQL的sql_mode模式说明及设置
  • 原文地址:https://www.cnblogs.com/hit-yhj/p/6695366.html
Copyright © 2020-2023  润新知