基于FPGA的手柄遥控排爆机器人

2024-01-26 09:20

本文主要是介绍基于FPGA的手柄遥控排爆机器人,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

FPGA开发之 游戏手柄遥控排爆机器人

  • 使用对象:PS2游戏手柄,L298N电机驱动模块,履带底盘,6自由度机械臂
  • 使用环境:ISE14.7和BASYS2开发板

1.排爆机器人展示

这里写图片描述

这里写图片描述
整体原理简介
该排爆机器人硬件部分为一个履带底盘和一个6自由度的机械臂,通过PS2游戏手柄遥控,fpga开发板接收遥控信号并控制机器人的运动,输出6路PWM波控制6自由度机械臂,还有2路pwm波控制底盘电机。

2.Verilog代码实现

所用PS2游戏手柄的SPI协议解析和输出PWM波的原理可以参考代码注释和我的前两篇博客

`timescale 1ns / 1ps
module spi_control_pwm(input clk,              //板载50Mhz时钟信号input reset,的output [7:0] ledout,       //板上八个LED灯亮,指示正常工作状态以及第四个接收到byteoutput spi_clk,         //SPI通讯时钟线output spi_cs,          //SPI通讯片选信号线output spi_mosi,        //SPI通讯写端口input spi_miso,         //SPI通讯读端口inout [7:0] pwm_out,    //八路PWM输出output [3:0] motor_io     //控制电机正反转);
reg [1:0] moto1=0;    //控制电机正反转,原理参考L298N电机驱动模块原理图
reg [1:0] moto2=0;
reg [7:0] data_out; 
reg [7:0] data_in1;    //接收到的数据,八位的字节
reg [7:0] data_in2;
reg [7:0] data_in3;
reg [7:0] data_in4;
reg [7:0] data_in5;
reg [7:0] data_in6;
reg sclk=1;          //SPI通讯时钟线  
reg smosi=1;           //SPI通讯写
reg smiso=0;           //SPI通讯读
reg scs;                //SPI通讯片选信号
reg [9:0] cnt_clk_6us=0;
reg clk_6us=1;
reg [15:0] cnt_1020us=0;
reg clk_1020us=0;
reg [7:0] led_set=0;
reg trig=1;
reg [3:0] count_for_trig=0;
reg [7:0] count_trig=0;
reg [3:0] motor_set=0;
reg [7:0] pwm_set=0;
reg [19:0] count_for_pwmclk=0;
reg pwm_clk=0;
always @(posedge clk)
beginif(cnt_clk_6us == 10'b00_1001_0110-1) begin     //产生6us信号cnt_clk_6us <= 0;clk_6us <= ~clk_6us;   //按位取反endelsecnt_clk_6us <= cnt_clk_6us + 1;if(cnt_1020us == 16'b0110_0011_1001_1100-1) begin    //周期1020uscnt_1020us <= 0;clk_1020us <= ~clk_1020us;  endelsecnt_1020us <= cnt_1020us + 1;if(count_for_pwmclk == 20'b0000_0000_0000_1111_1010-1) begin    // 0.01ms触发一次,故pwm波形精度为0.01mscount_for_pwmclk <= 0;pwm_clk <= ~pwm_clk;   //按位取反endelsecount_for_pwmclk <= count_for_pwmclk + 1;
endreg [11:0] count_pwm=0;
reg [11:0] pwm_compare1=12'b0000_1001_0110;  //初值定在150,即1.5ms,是舵机的中位
reg [11:0] pwm_compare2=12'b0000_1001_0110;
reg [11:0] pwm_compare3=12'b0000_1001_0100;   //初值148,控制360度舵机  
reg [11:0] pwm_compare4=12'b0000_1001_0110;
reg [11:0] pwm_compare5=12'b0000_1001_0110;
reg [11:0] pwm_compare6=12'b0000_1001_0110;
reg [11:0] pwm_compare7=12'b0000_1001_0110;
reg [11:0] pwm_compare8=12'b0000_1001_0110;
reg [11:0] speed_temp;reg pwm_flag1=0;
reg pwm_flag2=0;
reg pwm_flag3=0;
reg pwm_flag4=0;
reg pwm_flag5=0;
reg pwm_flag6=0;
reg pwm_flag7=0;
reg pwm_flag8=0;always @( posedge clk_1020us)
begin
led_set<=data_in1;
count_for_trig<=count_for_trig+1;if (count_for_trig==4'b0001)trig<=0;else if (count_for_trig==4'b0010)trig<=1;else    if (count_for_trig==4'b1010)count_for_trig<=4'b0000;
end控制pwm信号/
always @(posedge scs)    //每10ms跟新一次PWM输出和电机驱动状态
beginif ((data_in1[4]==0)&(pwm_compare1<250))    //control pwm1pwm_compare1<=pwm_compare1+1;else if((data_in1[6]==0)&(pwm_compare1>50))pwm_compare1<=pwm_compare1-1;if ((data_in1[7]==0)&(pwm_compare2<250))    //control pwm2pwm_compare2<=pwm_compare2+1; else if((data_in1[5]==0)&(pwm_compare2>50))pwm_compare2<=pwm_compare2-1;if ((data_in2[2]==0)&(pwm_compare3<250))    //control pwm3  1.48ms控制360度舵机pwm_compare3<=pwm_compare3+1;else if((data_in2[3]==0)&(pwm_compare3>50))pwm_compare3<=pwm_compare3-1;if ((data_in2[6]==0)&(pwm_compare4<250))    //control pwm4pwm_compare4<=pwm_compare4+1;else if((data_in2[4]==0)&(pwm_compare4>50))pwm_compare4<=pwm_compare4-1;if ((data_in2[0]==0)&(pwm_compare5<250))        //control pwm5pwm_compare5<=pwm_compare5+1;else if((data_in2[1]==0)&(pwm_compare5>50))pwm_compare5<=pwm_compare5-1;if ((data_in2[7]==0)&(pwm_compare6<250))        //control pwm6pwm_compare6<=pwm_compare6+1;else if((data_in2[5]==0)&(pwm_compare6>50))pwm_compare6<=pwm_compare6-1;if ((data_in4<127)|(data_in4>132))      //检测左摇杆Y方向是否拨动beginif (data_in4<123)  //前进beginspeed_temp<=((~data_in4)&7'b01111111)<<4;if ((data_in5>126)&(data_in5<135)) //偏向拨杆没有拨动  beginpwm_compare7<=speed_temp;pwm_compare8<=speed_temp;endelse if (data_in5<127)beginpwm_compare8<=speed_temp-(((~data_in5)&7'b01111111)<<4);   //左右偏航pwm_compare7<=speed_temp;endelse if (data_in5>132)beginpwm_compare7<=speed_temp-((data_in5-128)<<4);pwm_compare8<=speed_temp;endmoto1<=2'b10;moto2<=2'b10;endelse if(data_in4>132) //后退beginmoto1<=2'b01;moto2<=2'b01;pwm_compare7<=(data_in4-128)<<3;pwm_compare8<=pwm_compare7;endendelse if((data_in4>126)&(data_in4<132))beginmoto1<=2'b00;moto2<=2'b00;if((data_in3<123)|(data_in3>132))    //原地左右转beginif (data_in3<123)beginpwm_compare7<=((~data_in3)&7'b01111111)<<3;pwm_compare8<=((~data_in3)&7'b01111111)<<3;moto1<=2'b10;moto2<=2'b01;endelse if (data_in3>132)beginpwm_compare7<=(data_in3-128)<<3;pwm_compare8<=(data_in3-128)<<3;moto1<=2'b01;moto2<=2'b10;endendendendalways @(posedge pwm_clk)    //控制八路pwm信号输出
begincount_pwm<=count_pwm+1;if (count_pwm < pwm_compare1)   //pwm1pwm_flag1<=1;elsepwm_flag1<=0;if (count_pwm < pwm_compare2)   //pwm2pwm_flag2<=1;elsepwm_flag2<=0;if (count_pwm < pwm_compare3)   //pwm3pwm_flag3<=1;elsepwm_flag3<=0;if (count_pwm < pwm_compare4)   //pwm4pwm_flag4<=1;elsepwm_flag4<=0;   if (count_pwm < pwm_compare5)   //pwm5pwm_flag5<=1;elsepwm_flag5<=0;if (count_pwm < pwm_compare6)   //pwm6pwm_flag6<=1;elsepwm_flag6<=0;if (count_pwm < pwm_compare7)   //pwm7pwm_flag7<=1;elsepwm_flag7<=0;if (count_pwm < pwm_compare8)   //pwm8pwm_flag8<=1;elsepwm_flag8<=0;   if (count_pwm ==12'b0111_1101_0000-1)count_pwm<=0;endalways @(negedge clk_6us)
beginif (trig==0)beginscs<=0;count_trig<=count_trig+1;//spi_clk波形产生if ((0<count_trig)&(count_trig<17))   //byte1sclk<=~sclk;else if ((19<count_trig)&(count_trig<36))  //byte2sclk<=~sclk;else if ((38<count_trig)&(count_trig<55))  //byte3sclk<=~sclk;else if ((57<count_trig)&(count_trig<74))  //byte4sclk<=~sclk;else if ((76<count_trig)&(count_trig<93))  //byte5sclk<=~sclk;else if ((95<count_trig)&(count_trig<112))  //byte6sclk<=~sclk;else if ((114<count_trig)&(count_trig<131))  //byte7sclk<=~sclk;else if ((133<count_trig)&(count_trig<150))  //byte8sclk<=~sclk;else if ((152<count_trig)&(count_trig<169))  //byte9sclk<=~sclk;///mosi波形产生///if (count_trig<2)smosi<=1;else if ((20<count_trig)&(count_trig<23))smosi<=1;else if ((30<count_trig)&(count_trig<33))smosi<=1;else smosi<=0;//读取misoif (count_trig==58)    //读byte4data_in1[0]<=spi_miso;else if (count_trig==60)data_in1[1]<=spi_miso;else if (count_trig==62)data_in1[2]<=spi_miso;else if (count_trig==64)data_in1[3]<=spi_miso;else if (count_trig==66)data_in1[4]<=spi_miso;else if (count_trig==68)data_in1[5]<=spi_miso;else if (count_trig==70)data_in1[6]<=spi_miso;else if (count_trig==72)data_in1[7]<=spi_miso;  if (count_trig==77)    //读byte5data_in2[0]<=spi_miso;else if (count_trig==79)data_in2[1]<=spi_miso;else if (count_trig==81)data_in2[2]<=spi_miso;else if (count_trig==83)data_in2[3]<=spi_miso;else if (count_trig==85)data_in2[4]<=spi_miso;else if (count_trig==87)data_in2[5]<=spi_miso;else if (count_trig==89)data_in2[6]<=spi_miso;else if (count_trig==91)data_in2[7]<=spi_miso;  if (count_trig==96)    //读byte6data_in3[0]<=spi_miso;else if (count_trig==98)data_in3[1]<=spi_miso;else if (count_trig==100)data_in3[2]<=spi_miso;else if (count_trig==102)data_in3[3]<=spi_miso;else if (count_trig==104)data_in3[4]<=spi_miso;else if (count_trig==106)data_in3[5]<=spi_miso;else if (count_trig==108)data_in3[6]<=spi_miso;else if (count_trig==110)data_in3[7]<=spi_miso;  if (count_trig==115)    //读byte7data_in4[0]<=spi_miso;else if (count_trig==117)data_in4[1]<=spi_miso;else if (count_trig==119)data_in4[2]<=spi_miso;else if (count_trig==121)data_in4[3]<=spi_miso;else if (count_trig==123)data_in4[4]<=spi_miso;else if (count_trig==125)data_in4[5]<=spi_miso;else if (count_trig==127)data_in4[6]<=spi_miso;else if (count_trig==129)data_in4[7]<=spi_miso;if (count_trig==134)    //读byte8data_in5[0]<=spi_miso;else if (count_trig==136)data_in5[1]<=spi_miso;else if (count_trig==138)data_in5[2]<=spi_miso;else if (count_trig==140)data_in5[3]<=spi_miso;else if (count_trig==142)data_in5[4]<=spi_miso;else if (count_trig==144)data_in5[5]<=spi_miso;else if (count_trig==146)data_in5[6]<=spi_miso;else if (count_trig==148)data_in5[7]<=spi_miso;if (count_trig==153)    //读byte8data_in6[0]<=spi_miso;else if (count_trig==155)data_in6[1]<=spi_miso;else if (count_trig==157)data_in6[2]<=spi_miso;else if (count_trig==159)data_in6[3]<=spi_miso;else if (count_trig==161)data_in6[4]<=spi_miso;else if (count_trig==163)data_in6[5]<=spi_miso;else if (count_trig==165)data_in6[6]<=spi_miso;else if (count_trig==167)data_in6[7]<=spi_miso;  endelse if(trig==1)beginscs<=1;sclk<=1;count_trig<=0;endendassign pwm_out[0]=pwm_flag1;
assign pwm_out[1]=pwm_flag2;
assign pwm_out[2]=pwm_flag3;
assign pwm_out[3]=pwm_flag4;
assign pwm_out[4]=pwm_flag5;
assign pwm_out[5]=pwm_flag6;
assign pwm_out[6]=pwm_flag7;
assign pwm_out[7]=pwm_flag8;
assign motor_io[0]=moto1[1];
assign motor_io[1]=moto1[0];
assign motor_io[2]=moto2[1];
assign motor_io[3]=moto2[0];
assign ledout = led_set;
assign spi_clk=sclk;
assign spi_cs=scs;
assign spi_cs=scs;
assign spi_mosi=smosi;endmodule

3.供电系统接法以及负载注意事项

本机器人上一共有五个电压档次
- 电池是22.4V,30C,6s的锂电池
- 电机是9V的直流电机
- 舵机驱动电压是6~7.4V
- FPGA开发板是5V的直流电压输出,通过板载电源芯片3.3V电压输出

下面分块验证负载情况

因为电池是2600mah,30C的航模锂电池,输出电流可以达到22V、7.8A,故采用两个稳压模块将22.4V电池电压分别降到和7V。每个稳压源最大输出电流5A。
这里写图片描述
这里写图片描述

对于电机驱动而言,我们采用的是L298N舵机驱动模块,电机的最大电流200mA,L298N的最大输出电流为2A,电机电流400mA小于L298N输出电流2A小于降压模块输出电流5A,故此路电流没有问题。
这里写图片描述

对于舵机而言,由于店家给不出工作电流
这里写图片描述

所以我实测了最大负载臂的驱动舵机峰值电流为1.1A
这里写图片描述
这样的六个舵机并联在一起,当舵机联动时负载电流可能超过稳压模块输出的5A,导致供电不足,系统重启。

以上供电系统任然有缺陷存在,写这些是为了提醒大家在做实物的时候需要考虑到供电问题以及一些模电知识,才能做出稳定可靠的系统。

这篇关于基于FPGA的手柄遥控排爆机器人的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/646334

相关文章

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)

《Python基于火山引擎豆包大模型搭建QQ机器人详细教程(2024年最新)》:本文主要介绍Python基于火山引擎豆包大模型搭建QQ机器人详细的相关资料,包括开通模型、配置APIKEY鉴权和SD... 目录豆包大模型概述开通模型付费安装 SDK 环境配置 API KEY 鉴权Ark 模型接口Prompt

基于树梅派的视频监控机器人Verybot

最近这段时间做了一个基于树梅派 ( raspberry pi ) 的视频监控机器人平台 Verybot ,现在打算把这个机器人的一些图片、视频、设计思路进行公开,并且希望跟大家一起研究相关的各种问题,下面是两张机器人的照片:         图片1:                   图片2                    这个平台的基本组成是:

FPGA编译与部署方法全方位介绍

FPGA编译与部署是FPGA开发中的核心环节,涉及从代码编写、调试到将设计部署到FPGA硬件的全过程。这个流程需要经过创建项目、编写FPGA VI、模拟调试、编译生成比特流文件,最后将设计部署到硬件上运行。编译的特点在于并行执行能力、定制化硬件实现以及复杂的时钟管理。通过LabVIEW的FPGA模块和NI硬件,可以快速完成开发和部署,尤其适用于复杂控制与高性能数据处理系统。 1. FPG

FPGA开发:条件语句 × 循环语句

条件语句 if_else语句 if_else语句,用来判断是否满足所给定的条件,根据判断的结果(真或假)决定执行给出的两种操作之一。 if(表达式)语句; 例如: if(a>b) out1=int1; if(表达式)         语句1; else         语句2; 例如: if(a>b)out1=int1;elseout1=int2; if(表达式1) 语句1; els

【机器人工具箱Robotics Toolbox开发笔记(二十)】机器人工具箱SerialLink I类函数参数说明

机器人工具箱中的SerialLink表示串联机器人型机器人的具体类。该类使用D-H参数描述,每个关节一组。SerialLink I类包含的参数如表1所示。 表1 SerialLink I类参数 参  数 意    义 参  数 意    义 plot 显示机器人的图形表示 jacobn 工具坐标系中的雅可比矩阵 plot3D 显示机器人3D图形模型 Jacob_dot

FPGA开发:模块 × 实例化

模块的结构 对于C语言,其基本单元为函数。与此类似,Verilog的基本设计单元称之为"模块"(block)。对于整个项目的设计思想就是模块套模块。 一个模块由两个部分组成:一部分描述接口,一部分描述逻辑功能。 每个Verilog模块包含4个部分:端口定义、IO说明、内部信号声明、功能定义。且位于module和endmodule之间,如下: module block(a,b,c);inpu

机器人助力上下料搬运,加速仓库转运自动化

近年来,国内制造业领域掀起了一股智能化改造的浪潮,众多工厂纷纷采纳富唯智能提供的先进物流解决方案,这一举措显著优化了生产流程,实现了生产效率的飞跃式增长。得益于这些成功案例,某信息技术服务企业在工厂智能物流建设的进程中,也选择了与富唯智能合作。 为了应对日益增长的物料搬运需求,匹配成品输出节拍,该公司引入了富唯智能复合机器人AMR与搬运机器人AGV,实现了仓库成品搬运自动化,大幅减少人工

LabVIEW环境中等待FPGA模块初始化完成

这个程序使用的是LabVIEW环境中的FPGA模块和I/O模块初始化功能,主要实现等待FAM(Field-Programmable Gate Array Module,FPGA模块)的初始化完成,并处理初始化过程中的错误。让我们逐步分析各部分的功能: 1. Wait for FAM Initialization框架 此程序框架用于等待I/O模块成功初始化。如果在5秒钟内模块没有完成配

【最新华为OD机试E卷-支持在线评测】机器人活动区域(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 94 分 最新华为OD机试目录: https://blog.