基於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

串口通信是熟悉板子的入門練習,可以深刻理解發送數據的方式,以及波特率的含義和計算。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM