关于小车,之前也写了好几期了,先给大家放一段视频,后面打算将机械臂集成到坦克上,目前还在调试中,夹具已经能够控制夹紧和松开了:
上次那辆小车的底盘实在是脆弱,一不小心就撞碎了,后面直接上了个坦克底盘,在基于坦克底盘的小车上,控制坦克行走和之前小车的方法一致,采用的是PWM直驱,通过改变占空比的形式让坦克前进、后退、左右转。此次加上各种模块,分别如下:
激光瞄准头
蜂鸣器报警(因为还没买电磁炮,所以暂时用来代替发射)
步进电机(用来调节发射瞄准角度)
MG996R舵机(打算做成360°旋转避障,据说会影响精度,还没试)
超声波模块SR04
游戏摇杆模块控制
这个没什么好说的,就跟点灯一样,高电平打开激光射线,低电平关闭激光射线,但我总觉得这个太暗了,改天一定要买一个亮度更大,效果看起来更明显的。
这里选用的是有源蜂鸣器,也是跟点灯一样,高低电平控制,当小车收到SHOT
指令时,发射炮弹,用蜂鸣器高电平的响声暂时代替,后续替换成电磁炮。
电机控制是一门非常高深的学问,如果想去走工控行业需要玩到电机方面的,那么步进电机一定少不了,不管怎么说,我们还是可以把它驱动起来的,以下是我买的一个步进电机驱动模块:
步进电机选用的型号是:28BYJ48-H12
这里在软件编程上有一个比较重要参数需要了解一下,就是步距角。
那么什么是步距角呢?度娘给你答案,可以详细看看。
https://baike.baidu.com/item/%E6%AD%A5%E8%B7%9D%E8%A7%92/5946465?fr=aladdin
来看看下面这个换算公式,或许你就明白了,如上图所示,步距角=5.625°/64,意思就是每64个脉冲步进电机就会转5.625度,因此我们很容易得出以下计算公式:电机转一圈有360°,那么转一圈的脉冲数 = 360 / 5.625 * 64 = 4096 个脉冲。进而很容易得到以下角度与脉冲的简单算法:
/*
Rotation_Angle:旋转角度
返回:Motor_Pulse 根据公式计算得出的脉冲个数
*/
int Motor_Angle_Cal(int Rotation_Angle)
{
if(Rotation_Angle < 0 || Rotation_Angle > 360)
return -1 ;
Motor_Pulse = (int)((double)(Rotation_Angle / 5.625) * 64) ;
return Motor_Pulse ;
}
关于详细配置和程序编写,之前在CSDN博客上也已经做过类似的笔记,这里就不重复写了:
https://yangyuanxin.blog.csdn.net/article/details/100901635
关于舵机控制,我想世伟之前写的文章介绍就已经非常详细了,链接如下:
STM32Cube-21(补充) | 使用通用定时器产生PWM驱动舵机
这里的舵机我让它以固定频率进行360旋转,这个效果感觉像激光雷达哈哈哈,有时间一定买个来玩玩。
主要用来实现测距避障用,引用之前学习32时听了温老师的课,这是他的课堂笔记,我觉得下面这个图理解起来超级通俗易懂了,文末回复关键字获取。
根据模块提供的手册,下面来了解下工作原理以及如何来应用
看到这里我们就明白了,x,y是模拟量,而z是一个二值数据,在这里,可以利用STM32的ADC控制器来读取X,Y的输出,Z轴就很简单了,把它当作普通按键就可以了,关于ADC介绍,温老师的笔记值得收藏,通俗易懂。
关于游戏摇杆模块控制小车,其实只要把摇杆方向的AD值测出来,然后写个简单的函数进行区分就可以了,以下是我实测的控制数据,可能并不是特别精准,但个人觉得够用了,后期也可以进行优化:
//通过DMA通道转换得到的值
uint32_t JOY_VALUE[2];
//保存转换计算后的电压值
__IO float ADC_VOL_VALUE[2];
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
#define LEFT_UP 4
#define LEFT_DOWN 5
#define RIGHT_UP 6
#define RIGHT_DONW 7
#define ENTER 8
#define UNKNOW_KEY 99
//获取摇杆键值
uint8_t GET_KEY_VALUE(int x, int y, int z)
{
if((0 == x) && (y > 50 && y < 255))
return UP;
else if((255 == x) && (y > 0 && y < 255))
return DOWN ;
else if((x > 0 && x < 255) && (255 == y))
return LEFT ;
else if((x > 0 && x < 255) && (0 == y))
return RIGHT ;
else if((0 == x) && (255 == y))
return LEFT_UP ;
else if((255 == x) && (255 == y))
return LEFT_DOWN ;
else if((0 == x) && (0 == y))
return RIGHT_UP ;
else if((255 == x) && (0 == y))
return RIGHT_DONW ;
else if(x > 0 && y > 0 && 0 == z)
return ENTER ;
return UNKNOW_KEY ;
}
要控制小车,那么就要把WIFI和摇杆模块的控制绑定起来,首先肯定是要让WIFI进入透传模式,然后通过WIFI发送控制指令给小车,核心代码如下:
int main(void)
{
/* USER CODE BEGIN 1 */
int JOY_X, JOY_Y, JOY_Z ;
uint8_t key_value ;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_USART3_UART_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
ESP8266_Init();
printf("正在配置 ESP8266 ......\n" );
if(ESP8266_AT_Test())
{
printf("AT test OK\n");
}
printf("\n< 1 >\n");
if(ESP8266_Net_Mode_Choose(STA))
{
printf("ESP8266_Net_Mode_Choose OK\n");
}
printf("\n< 2 >\n");
while(!ESP8266_JoinAP(User_ESP8266_ApSsid, User_ESP8266_ApPwd));
printf("\n< 3 >\n");
ESP8266_Enable_MultipleId(DISABLE);
while(!ESP8266_Link_Server(enumTCP, User_ESP8266_TcpServer_IP, User_ESP8266_TcpServer_Port, Single_ID_0));
printf("\n< 4 >\n");
while(!ESP8266_UnvarnishSend());
printf("配置 ESP8266 完毕\n");
HAL_ADC_Start_DMA(&hadc1, JOY_VALUE, 2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//3.3V为AD转换的参考电压值,STM32的AD转换为12bit,所以2^12=4096
//故当输入参考电压为3.3V时,AD转换的结果为4096
//取12bit数值
//ADC_VOL_VALUE[0] = (float)(JOY_VALUE[0] & 0xFFF) * 3.3 / 4096 ;
//ADC_VOL_VALUE[1] = (float)(JOY_VALUE[1] & 0xFFF) * 3.3 / 4096 ;
//printf("x:%.2fv y:%.2fv\n", ADC_VOL_VALUE[0], ADC_VOL_VALUE[1]);
//只取8位有效数据
JOY_X = JOY_VALUE[0] & 0xFF;
JOY_Y = JOY_VALUE[1] & 0xFF;
JOY_Z = HAL_GPIO_ReadPin(JOY_Z_GPIO_Port, JOY_Z_Pin);
key_value = GET_KEY_VALUE(JOY_X, JOY_Y, JOY_Z);
//printf("x:%d y:%d z:%d\n", JOY_X, JOY_Y, JOY_Z);
switch(key_value)
{
//小车前进
case UP :
printf("上\n");
ESP8266_SendString(ENABLE,"GO",strlen("GO"),0);
break ;
//小车后退
case DOWN :
printf("下\n");
ESP8266_SendString(ENABLE,"BACK",strlen("BACK"),0);
break ;
//小车左转
case LEFT :
printf("左\n");
ESP8266_SendString(ENABLE,"LEFT",strlen("LEFT"),0);
break ;
//小车右转
case RIGHT :
printf("右\n");
ESP8266_SendString(ENABLE,"RIGHT",strlen("RIGHT"),0);
break ;
//控制步进电机向右旋转45°
case LEFT_UP:
printf("左上\n");
ESP8266_SendString(ENABLE,"MOTOR_RADJ",strlen("MOTOR_RADJ"),0);
break ;
case LEFT_DOWN:
printf("左下\n");
break ;
//控制步进电机向左旋转45°
case RIGHT_UP:
printf("右上\n");
ESP8266_SendString(ENABLE,"MOTOR_LADJ",strlen("MOTOR_LADJ"),0);
break ;
case RIGHT_DONW :
printf("右下\n");
break ;
//控制发射炮弹
case ENTER :
printf("确认\n");
ESP8266_SendString(ENABLE,"SHOT",strlen("SHOT"),0);
break ;
//控制小车停止
default:
ESP8266_SendString(ENABLE,"STOP",strlen("STOP"),0);
break ;
}
HAL_Delay(200);
}
/* USER CODE END 3 */
}
完整程序等我把小车DIY完,会把硬件模块、软件程序等全部开源,如需学习温老师的笔记,请在公众号后台回复STM32学习笔记
获取,本着分享原则,本资源从网上搜索获取,如有违规,请联系我删除,谢谢!
STM32在线升级OTA,看这一篇就够啦~
第10期 | ringbuff,通用FIFO环形缓冲区实现库
ESP8266实战贴:使用HTTP POST请求上传数据到公有云OneNet
会C/C++就可以开发Linux/Android应用程序?替代传统串口屏的Yoxios了解一下!
觉得本次分享的文章对您有帮助,随手点[在看]
并转发分享,也是对我的支持。