基于Robei:如何利用Lora与机器人进行无线通讯
文章目录
- 日常·唠嗑:
- 一、什么是Lora模块
- 二、通讯方式是什么
- 1、模块选择
- 2、参数及设置
- 3、接线方式
- 1、通信接线
- 2、参数修改接线
- 三、Robei程序设计
- 总结
日常·唠嗑:
今年华南赛区结束了,还有二十多天才进行国赛,也算是有几天清闲日子。对于Lora,我有着特殊的情感,从上届集创赛我就一直用到现在。起初我一直执着于WiFi模块,但是WiFi模块对FPGA小白程序员是一点都不友好,然后俩零同学就给我推荐了这款无线扩频模块。随着LoRa技术的不断成熟,现在LoRa已经在国内外得到广泛应用,在这个领域中的人对LoRa并不陌生。LoRa是一种专用于远距离低功耗的无线通信技术,其调制方式相对于其他通信方式大大增加了通信距离,可广泛应用于各种场合的远距离低速率物联网无线通信领域。下面就简单说说如何在Robei中设计Lora与机器人通讯。
一、什么是Lora模块
要了解LoRa模块就要先了解LoRa,LoRa是低功耗广域网通信技术中的一种,是Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输技术,是Semtech 射频部分产生的一种独特的调制格式。LoRa模块就是基于Semtech公司SX1276/1278芯片研发的无线数传模块,这种芯片集成规模小、效率高,从而让LoRa模块拥有高接收灵敏度。
LoRa的优势主要体现在以下几个方面:
1、大大的改善了接收的灵敏度,降低了功耗。
高达157db的链路预算使其通信距离可达15公里(与环境有关)。其接收电流仅10mA,睡眠电流200nA,这大大延迟了电池的使用寿命。
2、基于该技术的网关/集中器支持多信道多数据速率的并行处理,系统容量大。
网关是节点与IP网络之间的桥梁(通过2G/3G/4G或者Ethernet)。每个网关每天可以处理500万次各节点之间的通信(假设每次发送10Bytes,网络占用率10%)。如果把网关安装在现有移动通信基站的位置,发射功率20dBm(100mW),那么在建筑密集的城市环境可以覆盖2公里左右,而在密度较低的郊区,覆盖范围可达10公里。
3、基于终端和集中器/网关的系统可以支持测距和定位。
LoRa对距离的测量是基于信号的空中传输时间而非传统的RSSI(Received Signal Sterngth Ind-ication),而定位则基于多点(网关)对一点(节点)的空中传输时间差的测量。其定位精度可达5m(假设10km的范围)。
4、高保密性、高隐蔽性
采用LoRa调制方式,传统无线设备无法对其进行获、解析,带内平均功率低于底噪时仍然可以正常通讯。
二、通讯方式是什么
1、模块选择
某宝的lora模块有很多种,选择哪种模块呢?
建议选择亿佰特,他们家是专门做lora模块的,有各种型号,价格也很便宜,模块加天线,两套才31RMB。而且他们家的模块,写起程序来要比其他的方便很多,想正点原子的lora模块就很麻烦,进行通讯还要配置各种环境。用亿佰特的,只要以UART协议 进行程序编写就行了。
2、参数及设置
我选择的是,E32-433T20DC LoRa扩频 ,一下是他的参数:
芯片方案:SX1278
载波频率:410~441MHz
发射功率:10~20dBm
通信距离:3km
通信接口:UART
默认波特率:9600
产品净量:6.3±0.1g
产品简介:其嵌入高速低功耗单片机和高性能LoRa扩频芯片SX1278,采用高效的循环交织纠检错编码,抗干扰和灵敏度都大大提高。发射功率100mW,低功耗,具有无线唤醒功能,LoRa扩频能够带来更远的通讯距离。
这里提一下,他的波特率是默认9600的,你可以在他们官网下载APP修改波特率以及其他参数。
3、接线方式
1、通信接线
从下图可以看到,模块有7个排针,1-7号,M1,M2主要是选择工作模式,一般通信模式需要将这两个引脚接地(可以拿面包板将这两个引脚跟7引脚GND接在一起),3是RXD接开发板的TXD,4是TXD开发板RXD;5引脚不用理,悬空就好;6是VCC,接电源3.3V-5V。
这里我觉得接面包板线太多,又乱,就画了快简单的扩展板:
有了扩展板,这样就很方便了,就像普通的串口通讯一样。
2、参数修改接线
上面说到,可以通过官网的软件修改模块波特率,修改参数的话,主要是在上一小节的基础上,将M1,M2置高电平, 也就是拉高。下面看一下模块的工作选择表;接线完,直接通过CH340模块接到电脑,打开APP读取参数,修改,保存就好了。
三、Robei程序设计
1、首先构建顶层,打开Robei EDA,new一个module:robei_lora
module robei_lora(sys_clk,sys_rst_n,uart_rxd,uart_txd);//----Parameters:: generated by Robei-----parameter CLK_FREQ = 50000000;parameter UART_BPS = 9600;//---Ports declearation: generated by Robei---input sys_clk;input sys_rst_n;input uart_rxd;output uart_txd;wire sys_clk;wire sys_rst_n;wire uart_rxd;wire uart_txd;//----Code starts here: integrated by Robei-----wire uart_en_w; //UART发送使能wire [7:0] uart_data_w; //UART发送数据wire clk_1m_w; //1MHz时钟,用于Signaltap调试//---Module instantiation---lora_send #( 50000000, 9600) lora_send1(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.uart_en(uart_en_w),.uart_din(uart_data_w),.uart_txd(uart_txd));lora_recv #( 50000000, 9600) lora_recv2(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.uart_rxd(uart_rxd),.uart_done(uart_en_w),.uart_data(uart_data_w));endmodule //robei_lora
2、写一个接收模块:lora_recv
module lora_recv(sys_clk,sys_rst_n,uart_rxd,uart_done,uart_data);//----Parameters:: generated by Robei-----parameter CLK_FREQ = 50000000;parameter UART_BPS = 9600;//---Ports declearation: generated by Robei---input sys_clk;input sys_rst_n;input uart_rxd;output uart_done;output [7:0] uart_data;wire sys_clk;wire sys_rst_n;wire uart_rxd;reg uart_done;reg [7:0] uart_data;//----Code starts here: integrated by Robei-----localparam BPS_CNT = CLK_FREQ/UART_BPS; //为得到指定波特率,//需要对系统时钟计数BPS_CNT次//reg definereg uart_rxd_d0;reg uart_rxd_d1;reg [15:0] clk_cnt; //系统时钟计数器reg [ 3:0] rx_cnt; //接收数据计数器reg rx_flag; //接收过程标志信号reg [ 7:0] rxdata; //接收数据寄存器//wire definewire start_flag;//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号assign start_flag = uart_rxd_d1 & (~uart_rxd_d0); //对UART接收端口的数据延迟两个时钟周期always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin uart_rxd_d0 <= 1'b0;uart_rxd_d1 <= 1'b0; endelse beginuart_rxd_d0 <= uart_rxd; uart_rxd_d1 <= uart_rxd_d0;end end//当脉冲信号start_flag到达时,进入接收过程 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) rx_flag <= 1'b0;else beginif(start_flag) //检测到起始位rx_flag <= 1'b1; //进入接收过程,标志位rx_flag拉高else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))rx_flag <= 1'b0; //计数到停止位中间时,停止接收过程elserx_flag <= rx_flag;endend//进入接收过程后,启动系统时钟计数器与接收数据计数器always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin clk_cnt <= 16'd0; rx_cnt <= 4'd0;end else if ( rx_flag ) begin //处于接收过程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;rx_cnt <= rx_cnt;endelse beginclk_cnt <= 16'd0; //对系统时钟计数达一个波特率周期后清零rx_cnt <= rx_cnt + 1'b1; //此时接收数据计数器加1endendelse begin //接收过程结束,计数器清零clk_cnt <= 16'd0;rx_cnt <= 4'd0;endend//根据接收数据计数器来寄存uart接收端口数据always @(posedge sys_clk or negedge sys_rst_n) begin if ( !sys_rst_n) rxdata <= 8'd0; else if(rx_flag) //系统处于接收过程if (clk_cnt == BPS_CNT/2) begin //判断系统时钟计数器计数到数据位中间case ( rx_cnt )4'd1 : rxdata[0] <= uart_rxd_d1; //寄存数据位最低位4'd2 : rxdata[1] <= uart_rxd_d1;4'd3 : rxdata[2] <= uart_rxd_d1;4'd4 : rxdata[3] <= uart_rxd_d1;4'd5 : rxdata[4] <= uart_rxd_d1;4'd6 : rxdata[5] <= uart_rxd_d1;4'd7 : rxdata[6] <= uart_rxd_d1;4'd8 : rxdata[7] <= uart_rxd_d1; //寄存数据位最高位default:; endcaseendelse rxdata <= rxdata;elserxdata <= 8'd0;end//数据接收完毕后给出标志信号并寄存输出接收到的数据always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) beginuart_data <= 8'd0; uart_done <= 1'b0;endelse if(rx_cnt == 4'd9) begin //接收数据计数器计数到停止位时 uart_data <= rxdata; //寄存输出接收到的数据uart_done <= 1'b1; //并将接收完成标志位拉高endelse beginuart_data <= 8'd0; uart_done <= 1'b0; end endendmodule //lora_recv
3、写一个发送模块:lora_send
module lora_send(sys_clk,sys_rst_n,uart_en,uart_din,uart_txd);//----Parameters:: generated by Robei-----parameter CLK_FREQ = 50000000;parameter UART_BPS = 9600;//---Ports declearation: generated by Robei---input sys_clk;input sys_rst_n;input uart_en;input [7:0] uart_din;output uart_txd;wire sys_clk;wire sys_rst_n;wire uart_en;wire [7:0] uart_din;reg uart_txd;//----Code starts here: integrated by Robei-----localparam BPS_CNT = CLK_FREQ/UART_BPS; //为得到指定波特率,对系统时钟计数BPS_CNT次//reg definereg uart_en_d0; reg uart_en_d1; reg [15:0] clk_cnt; //系统时钟计数器reg [ 3:0] tx_cnt; //发送数据计数器reg tx_flag; //发送过程标志信号reg [ 7:0] tx_data; //寄存发送数据//wire definewire en_flag;//捕获uart_en上升沿,得到一个时钟周期的脉冲信号assign en_flag = (~uart_en_d1) & uart_en_d0;//对发送使能信号uart_en延迟两个时钟周期always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) beginuart_en_d0 <= 1'b0; uart_en_d1 <= 1'b0;end else begin uart_en_d0 <= uart_en; uart_en_d1 <= uart_en_d0; endend//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin tx_flag <= 1'b0;tx_data <= 8'd0;end else if (en_flag) begin //检测到发送使能上升沿 tx_flag <= 1'b1; //进入发送过程,标志位tx_flag拉高tx_data <= uart_din; //寄存待发送的数据endelse if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))begin //计数到停止位中间时,停止发送过程tx_flag <= 1'b0; //发送过程结束,标志位tx_flag拉低tx_data <= 8'd0;endelse begintx_flag <= tx_flag;tx_data <= tx_data;end end//进入发送过程后,启动系统时钟计数器与发送数据计数器always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin clk_cnt <= 16'd0; tx_cnt <= 4'd0;end else if (tx_flag) begin //处于发送过程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;tx_cnt <= tx_cnt;endelse beginclk_cnt <= 16'd0; //对系统时钟计数达一个波特率周期后清零tx_cnt <= tx_cnt + 1'b1; //此时发送数据计数器加1endendelse begin //发送过程结束clk_cnt <= 16'd0;tx_cnt <= 4'd0;endend//根据发送数据计数器来给uart发送端口赋值always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) uart_txd <= 1'b1; else if (tx_flag)case(tx_cnt)4'd0: uart_txd <= 1'b0; //起始位 4'd1: uart_txd <= tx_data[0]; //数据位最低位4'd2: uart_txd <= tx_data[1];4'd3: uart_txd <= tx_data[2];4'd4: uart_txd <= tx_data[3];4'd5: uart_txd <= tx_data[4];4'd6: uart_txd <= tx_data[5];4'd7: uart_txd <= tx_data[6];4'd8: uart_txd <= tx_data[7]; //数据位最高位4'd9: uart_txd <= 1'b1; //停止位default: ;endcaseelse uart_txd <= 1'b1; //空闲时发送端口为高电平endendmodule //lora_send
4、将这两个子模块加进顶层模块连线就行了。
5、实物图
下位机:
上位机:
通过接线后就可以实现上位机与下位机回环通信。
也许有同学需要用到的是,下位机发送指定指令给上位机,比如人体检测模块检测到人的时候向上位机发送发现人员,这里一并满足大家。
按下按键后,开发板通过Lora向上位机发送:Fa Xian,需要其他指令的同学可以自己修改。
module UART(clk, rst, rxd, txd, en, seg_data, key_input, lowbit);
input clk,rst;
input rxd; //串行数据接收端
input key_input; //按键输入
output[7:0] en /*synthesis keep*/ ;
output[7:0] seg_data;
reg[7:0] seg_data;
output txd; //串行数据发送端
output lowbit;//***************************inner reg*******************************//
reg[15:0] div_reg; //分频计数器,分频值由波特率决定。分频后得到频率8倍波特率的时钟
reg[2:0] div8_tras_reg; //该寄存器的计数值对应发送时当前位于的时隙数
reg[2:0] div8_rec_reg; //该寄存器的计数值对应接收时当前位于的时隙数
reg[3:0] state_tras; //发送状态寄存器
reg[3:0] state_rec; //接受状态寄存器
reg clkbaud_tras; //以波特率为频率的发送使能信号
reg clkbaud_rec; //以波特率为频率的接受使能信号
reg clkbaud8x; //以8倍波特率为频率的时钟,它的作用是将发送或接受一个bit的时钟周期分为8个时隙
reg recstart; //开始发送标志
reg recstart_tmp;
reg trasstart; //开始接受标志
reg rxd_reg1; //接收寄存器1
reg rxd_reg2; //接收寄存器2,因为接收数据为异步信号,故用两级缓存
reg txd_reg; //发送寄存器
reg[7:0] rxd_buf /*synthesis keep*/ ; //接受数据缓存
reg[7:0] txd_buf /*synthesis keep*/ ; //发送数据缓存
reg[2:0] send_state /*synthesis keep*/ ; //每次按键给PC发送"Welcome"字符串,这是发送状态寄存器
reg[19:0] cnt_delay; //延时去抖计数器
reg start_delaycnt; //开始延时计数标志
reg key_entry1, key_entry2;//确定有键按下标志
parameter div_par = 16'h145; //分频参数,其值由对应的波特率计算而得,按此参数分频的时钟频率是波倍特率的8
//倍,此处值对应9600的波特率,即分频出的时钟频率是9600*8 (CLK 50M)
//**********************************************************//
assign txd = txd_reg;
assign lowbit = 0;
assign en = 0; //7段数码管使能信号赋值
//**********************************************************//
always@(posedge clk)
begin
if(!rst) begin
cnt_delay <= 0;
start_delaycnt <= 0; end
else if(start_delaycnt) begin
if(cnt_delay != 20'd800000) begin
cnt_delay <= cnt_delay + 1;end
else begin
cnt_delay <= 0;
start_delaycnt <= 0; end end
else begin
if(!key_input && cnt_delay == 0)
start_delaycnt <= 1; end
end
//**********************************************************//
always@(posedge clk)
begin
if(!rst)
key_entry1 <= 0;
else begin
if(key_entry2)
key_entry1 <= 0;
else if(cnt_delay == 20'd800000) begin
if(!key_input)
key_entry1 <= 1; end end
end
//**********************************************************//
always@(posedge clk)
begin
if(!rst)
div_reg <= 0;
else begin
if(div_reg == div_par - 1)
div_reg <= 0;
else
div_reg <= div_reg + 1; end
end
//**********************************************************//
always@(posedge clk) //分频得到8倍波特率的时钟
begin
if(!rst)
clkbaud8x <= 0;
else if(div_reg == div_par - 1)
clkbaud8x <= ~clkbaud8x;
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)
begin
if(!rst)
div8_rec_reg <= 0;
else if(recstart) //接收开始标志
div8_rec_reg <= div8_rec_reg + 1; //接收开始后,时隙数在8倍波特率的时钟下加1循环
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)
begin
if(!rst)
div8_tras_reg <= 0;
else if(trasstart)
div8_tras_reg <= div8_tras_reg + 1; //发送开始后,时隙数在8倍波特率的时钟下加1循环
end
//**********************************************************//
always@(div8_rec_reg)
begin
if(div8_rec_reg == 7)
clkbaud_rec = 1; //在第7个时隙,接收使能信号有效,将数据打入
else
clkbaud_rec = 0;
end
//**********************************************************//
always@(div8_tras_reg)
begin
if(div8_tras_reg == 7)
clkbaud_tras = 1; //在第7个时隙,发送使能信号有效,将数据发出
else
clkbaud_tras = 0;
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)
begin
if(!rst) begin
txd_reg <= 1;
trasstart <= 0;
txd_buf <= 0;
state_tras <= 0;
send_state <= 0;
key_entry2 <= 0; end
else begin
if(!key_entry2) begin
if(key_entry1) begin
key_entry2 <= 1;
txd_buf <= 8'd70; end end//"F"
else begin
case(state_tras)
4'b0000: begin //发送起始位
if(!trasstart && send_state < 7)
trasstart <= 1;
else if(send_state < 7) begin
if(clkbaud_tras) begin
txd_reg <= 0;
state_tras <= state_tras + 1;end end
else begin
key_entry2 <= 0;
state_tras <= 0; end end
4'b0001: begin //发送第1位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0010: begin //发送第2位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0011: begin //发送第3位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0100: begin //发送第4位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0101: begin //发送第5位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0110: begin //发送第6位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b0111: begin //发送第7位
if(clkbaud_tras) begin
txd_reg <= txd_buf[0];
txd_buf[6:0] <= txd_buf[7:1];
state_tras <= state_tras + 1; end end
4'b1000: begin //发送第8位
if(clkbaud_tras) begin
txd_reg<=txd_buf[0];
txd_buf[6:0]<=txd_buf[7:1];
state_tras<=state_tras+1;
end
end
4'b1001: begin //发送停止位
if(clkbaud_tras) begin
txd_reg<=1;
txd_buf<=8'h55;
state_tras<=state_tras+1;
end
end
4'b1111:begin
if(clkbaud_tras) begin
state_tras<=state_tras+1;
send_state<=send_state+1;
trasstart<=0;
case(send_state)
3'b000:
txd_buf<=8'd97;//"a"
3'b001:
txd_buf<=8'd32;//" "
3'b010:
txd_buf<=8'd88;//"X"3'b011:
txd_buf<=8'd105;//"i"
3'b100:
txd_buf<=8'd97;//"a"
3'b101:
txd_buf<=8'd110;//"n"
3'b111:
txd_buf<=8'd110;//"n"/*
3'b011:
txd_buf<=8'd82;//"R"
3'b100:
txd_buf<=8'd101;//"e"
3'b101:
txd_buf<=8'd110;//"n"
3'b111:
txd_buf<=8'd132;//" "
*/default:
txd_buf<=0;
endcase
end
end
default: begin
if(clkbaud_tras) begin
state_tras<=state_tras+1;
trasstart<=1;
end
end
endcase
end
end
end
//**********************************************************//
always@(posedge clkbaud8x or negedge rst)//接受PC机的数据
begin
if(!rst) begin
rxd_reg1<=0;
rxd_reg2<=0;
rxd_buf<=0;
state_rec<=0;
recstart<=0;
recstart_tmp<=0;
end
else begin
rxd_reg1<=rxd;
rxd_reg2<=rxd_reg1;
if(state_rec==0) begin
if(recstart_tmp==1) begin
recstart<=1;
recstart_tmp<=0;
state_rec<=state_rec+1;
end
else if(!rxd_reg1&&rxd_reg2) //检测到起始位的下降沿,进入接受状态
recstart_tmp<=1;
end
else if(state_rec>=1&&state_rec<=8) begin
if(clkbaud_rec) begin
rxd_buf[7]<=rxd_reg2;
rxd_buf[6:0]<=rxd_buf[7:1];
state_rec<=state_rec+1;
end
end
else if(state_rec==9) begin
if(clkbaud_rec) begin
state_rec<=0;
recstart<=0;
end
end
end
end
always@(rxd_buf) //将接受的数据用数码管显示出来
begin
case (rxd_buf)
8'h30: seg_data=8'b11000000;
8'h31: seg_data=8'b11111001;
8'h32: seg_data=8'b10100100;
8'h33: seg_data=8'b10110000;
8'h34: seg_data=8'b10011001;
8'h35: seg_data=8'b10010010;
8'h36: seg_data=8'b10000010;
8'h37: seg_data=8'b11111000;
8'h38: seg_data=8'b10000000;
8'h39: seg_data=8'b10010000;
8'h41: seg_data=8'b10001000;//a
8'h42: seg_data=8'b10000011;
8'h43: seg_data=8'b11000110;
8'h44: seg_data=8'b10100001;
8'h45: seg_data=8'b10000110;
8'h46: seg_data=8'b10001110;
default: seg_data=8'b11111111;
endcase
end
endmodule//本模块的功能是验证实现和PC机进行基本的串口通信的功能。需要在
//PC机上安装一个串口调试工具来验证程序的功能。
//程序实现了一个收发一帧10个bit(即无奇偶校验位)的串口控
//制器,10个bit是1位起始位,8个数据位,1个结束
//位。串口的波特律由程序中定义的div_par参数决定,更改该参数可以实
//现相应的波特率。程序当前设定的div_par 的值是0x145,对应的波特率是
//9600。用一个8倍波特率的时钟将发送或接受每一位bit的周期时间
//划分为8个时隙以使通信同步.
//程序的工作过程是:串口处于全双工工作状态,按动key1,FPGA/CPLD向PC发送“Fa Xian"
//字符串(串口调试工具设成按ASCII码接受方式);PC可随时向FPGA/CPLD发送0-F的十六进制
//数据,FPGA接受后显示在7段数码管上。
总结
洋洋洒洒写了两个晚上,很多东西都好没整理好,后面有时间会继续更新。比如,上位机通过Lora向开发板发送指令后将数据缓存到RAM中,有兴趣的同学在评论回留言: 对缓存数据有兴趣。人多的话,我会抽空写一下这个内容。
有其他问题的同学,可以加我好友,有看到会回答你的疑问,还有我们有不眠者技术交流群,可以进来互相学习。
基于Robei:如何利用Lora与机器人进行无线通讯相关推荐
- 基于CT取电LoRa传输的无源无线电流互感器应用方案
无线互感器用于 380V,频率 50~60Hz 的低压开关柜线 缆状态监测.将产品安装在待监测部位,传感器贴 紧电缆,准确闭合 互感器.监测回路电流大于产品启动电 流(3A),传感器进入正常工作模式, ...
- Lora和Zigbee无线通讯技术的对比
物联网应用中的无线技术有很多种,从大的方向分为两种,一种是局域网,另外一种是广域网. 最常见的广域网,是基于电信公司网络通讯的无线技术,例如2G,3G,4G,5G等,以及现在比较流行的NB-Iot. ...
- Crawler:基于Crawler和P2P技术实现机器人智能在线下载
Crawler:基于Crawler和P2P技术实现机器人智能在线下载 目录 实现功能 设计界面 操作步骤 实现功能 设计界面如下,输入你想要获取资料(包括图片.音乐.视频.大电影等)的网址,在线机器人 ...
- 基于气动人工肌肉的双足机器人关节设计
介绍了一种由气动人工肌肉构建的双足机器人关节,该关节利用气动人工肌肉的柔性特性,可以有效控制双足机器人快速行走或跑步时的落地脚冲击问题. 详细给出了气动人工肌肉的工作原理以及由其构成的关节系统的硬件架 ...
- 树莓派红外避障小车python_基于树莓派的环保“捡垃圾”机器人小车(避障、摄像、红外、WIFI)...
项目:基于树莓派的环保"捡垃圾"机器人小车控制平台 功能:避障.锁定某个障碍物 概述: 目前这个控制平台能够识别是"垃圾"只是塑料瓶,核心是利用Arduino控 ...
- 【机器视觉系统】基于3DOF机械臂的五子棋机器人(1)
基于3DOF机械臂的五子棋机器人 文章目录 基于3DOF机械臂的五子棋机器人 1. 前言 2. 机器视觉系统概述 2.1 机器 2.2 视觉 2.3 系统 3. 系统组成概述 3.1 使用工具盘点 3 ...
- 基于解剖特征的ACL重建机器人定位系统
基于解剖特征的ACL重建机器人定位系统 An ACL reconstruction robotic positioning system based on anatomical characteris ...
- 多机器人路径规划的代码_泛在电力物联网 | 基于IACOABC 算法的变电站巡检机器人路径规划...
区块链 | 方 响等 分布式新能源接入下的区块链共识机制研究 区块链 | 颜 拥等 基于区块链的电力数据保全应用研究 区块链 | 能源互联网中的区块链应用:优势.场景与案例 <浙江电力>2 ...
- 初中计算机教案3D,基于3D 仿真平台的初中机器人 教学设计
原标题:基于3D 仿真平台的初中机器人 教学设计 本文发表于 <数字教育> 2018年第5期(总第23期)实践案例栏目,页码:71-77.转载请注明出处. 摘 要:本文采用实践教学法,以社 ...
最新文章
- 为什么free()时不需要传指针大小
- Kibana模块——介绍
- 【Indiegogo众筹】$99高性价比RK3399超小型mini主机
- 微软.NET年芳15:我在Azure上搭建Photon服务器(C#.NET)
- 学姐百度实习面经(轻松拿offer)
- HEVC/H265 HM10.0 分析(三)TAppDecTop.cpp
- java scanner转string,Java InputStream to String 转化
- 大厂面试算法系列-如何从无序链表中移除重复项(二)-递归法
- 如何获取母版页上控件的值?
- 阶段1 语言基础+高级_1-3-Java语言高级_05-异常与多线程_第6节 Lambda表达式_2_冗余的Runnable代码...
- 华泰证券首席培训张继强 债市分析框架PPT
- 备忘--moodle安装
- 阻击 瑞星 和 雅虎助手 的 SVOHOST.exe(第2版)
- js通过pako压缩数据后java解压数据
- mysqldump参数之-A -B
- ios 全屏返回手势
- 禅道管理员admin密码登录失败,更改密码
- Android开发—简单的图片浏览器
- 【图基础】最佳入门课程:图卷积神经网络(中科院 计算所 沈华伟)
- 关于seekbar的thumb被截取的问题