使用3D打印材料制作全向轮 STM32作为主控使用HAL库 制作简单手柄并使用串口无线模块和主控进行通信

主要是第一次见到三轮全向底盘,进行全向移动对他的算法什么很感兴趣,如果能自己制作一辆全向轮底盘就好了

三轮全向小车模型

三轮全向的底盘网上售卖的店铺也很多也有着各种各样的选择不过价格有的也并不便宜所以打算自己弄一个(当然可能花费的更多但是也更有趣)

全向轮

网上在售的大多数以金属全向轮为主(中尺寸像是RoboMaster, RoboCount使用的),也有那种小一点的塑料轮子(金属轮子普遍不便宜)所以尝试自己画了个全向轮

这一版还有比较多的问题,比如留给棍子的空间太小了后面无法加装胶皮管
打印件一般摩擦力不是很大所以采用了小棍子外面包裹胶片软管的方式,效果杠杠的

3D打印并不是很好的选择一盘材料(1KG)中等一点的50左右 还有不到40的打印三个大概消耗了我半盘也并不是很便宜

SW软件中的装配图

实物图 (那些打印件是用偏口钳剪的,不然胶皮管会蹭到轮子)
螺丝螺母没买够只能找个长的替代了

底盘

三轮全向的地盘就好做一些了因为三个点确定一个面所以所有轮子不会悬空不加减震也没有关系,只要将三个轮子按照120°的角度固定就好
这里的电机模型是买了个电机找商家要的,这个电机挺好就是有的贵,后面测试没有用因为我就买了一个QAQ

硬件电路

主控选择

因为前段时间板子老烧所以手里没有什么可以使用的主控板子,一开始想使用ESP32的后来下载电路出了问题就没用,直接用了STM32F031C6T6的主控板 因为这个芯片很便宜做了5个开发板,这也是我第一次用立创EDA画的板子

不过这颗主控的定时器比较少没有办法使用AB编码器来测正反转速度
原理图(仅主控部分)
详细:https://oshwhub.com/watermelonnoodles/STM32F031C6T6_COR02

PCB

后面准备使用STM32F103ZET6正在画图中

电机驱动

使用直接购买的成品模块L298N
不是自己画的真是不好意思QAQ

下一版准备集成到开发板中可能使用双层板设计

电机选型

最开始在无刷和有刷直接选择,无刷还要进行驱动器的制作并且无刷电机也挺贵的后来直接选择了带有AB编码器的有刷电机,控起来也比较方便一些

一号电机什么都好就是太贵了一个大概就要50多
二号就比较中规中矩也挺好看的
三号也还可以不过他只有一相测速也就是说不能识别正反转

所以最后用了2号电机(因为都加了减速箱所以扭矩没太大问题)
所以电池电源也就定在了12V正好L298N上集成了宽电压转5V的降压

遥控端

大体思路是采用ADC手柄(XBOX那种)使用STM32F103C8T6进行采样过滤之后通过无线模块发送给主控端

原理图(主控引脚)因为在离线上还没有发布所以没有详细链接

PCB(之所以是方形是打算后面打印一个简单的外壳)

无线模块采用 汇承的HC-14 初学者套餐还是蛮优惠的 使用的是串口发送和接收
先在上位机设置好之后就可以装上了

接线

太晚了没法拍有时间或者有人需要在更新叭

软件调试

电机控制

HAL库配置

时钟树48MHz
开启 SYS — Debug Serial Wire
如果需要可以配置NVIC

PA0,1,2,3 不用管是用来测试步进电机的(没有用到)

定时器1 用来测速的ABC电机的A相接到Channel1,2,3上 B相没接 (后面没有用没法做闭环PID我只是拿来试试)

定时器PWM输出 三对 一共六个接口 用来控制电机的

定时器14(用来执行任务)开启NVIC

main.c的 /* USER CODE BEGIN 2 */ 下添加 完成PWM初始化

  /* USER CODE BEGIN 2 *//*电机代码*/HAL_TIM_Base_Start(&htim2); //TIM2HAL_TIM_Base_Start(&htim3); //TIM3HAL_TIM_Base_Start_IT(&htim14);HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);        // TIM2_CH1(pwm)HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);       // TIM2_CH2(pwm)HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);       // TIM3_CH1(pwm)HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);       // TIM3_CH2(pwm)HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);       // TIM3_CH3(pwm)HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);       // TIM3_CH4(pwm)/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

添加方法(这种只适用于测试这样写并不好 后面准备改一下创建一个电机的结构体)
可以添加到main方法上面/* USER CODE BEGIN 0 */区域

void Motor_set(int id,int speed){switch (id){case 3: // MotorCif(speed > 0){__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, speed);__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 0);}else{speed = speed * -1;__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 0);__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, speed);            }break;case 1: // MotorAif(speed > 0){__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, speed);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0);}else{speed = speed * -1;__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, speed); }break;case 2: // MotorBif(speed > 0){__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, speed);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);}else{speed = speed * -1;__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, speed); }break;}}

然后就可以判断那个电机是否都正常

遥控器处理

遥控器发送端 (是遥控器主板 并不是主控板)
HAL 配置

时钟树64MHz
开启 SYS — Debug Serial Wire
如果需要可以配置NVIC

主要使用的只有4个ADC以及串口

串口配置(刚发现竟然没用DMA 以后改进)开启NVIC

ADC配置 开启NVIC

定时器配置 开启NVIC

  /* USER CODE BEGIN 2 */HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adc_buff,4);adc_init();HAL_UART_Transmit_DMA(&huart2, str, sizeof(str) - 1); HAL_TIM_Base_Start_IT(&htim1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){//测试用HAL_Delay(50);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */

全局变量

uint16_t adc_buff[4];
int lx = 0, ly = 0, rx = 0, ry = 0;float adc_value[4];
uint8_t senda[10];

添加方法

// 用来上电做个校准不然偏差有点大
void adc_init(){HAL_Delay(20);Get_Data(adc_value,12);HAL_Delay(20);lx = 2000 - adc_value[0];ly = 2000 - adc_value[1];rx = 2000 - adc_value[2];ry = 2000 - adc_value[3];
}// 获取ADC摇杆数值并转化
static void Get_Data(float *temp,uint8_t times){uint32_t temp_val[4]={0};uint8_t t=0;for(t=0;t<times;t++){HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&adc_buff,4);temp_val[0]+=adc_buff[0];temp_val[1]+=adc_buff[1];temp_val[2]+=adc_buff[2];temp_val[3]+=adc_buff[3];
//    delay_ms(5);}//*3.3/4096temp[0]=(float)temp_val[0]/times;temp[1]=(float)temp_val[1]/times;temp[2]=(float)temp_val[2]/times;temp[3]=(float)temp_val[3]/times;// 卡尔曼滤波
//  temp[0] = KalmanFilter(temp[0]);
//  temp[1] = KalmanFilter(temp[1]);
//  temp[2] = KalmanFilter(temp[2]);
//  temp[3] = KalmanFilter(temp[3]);//四舍五入temp[0] = (int)(temp[0]*1000+0.5)/1000.0 + lx;temp[1] = (int)(temp[1]*1000+0.5)/1000.0 + ly;temp[2] = (int)(temp[2]*1000+0.5)/1000.0 + rx;temp[3] = (int)(temp[3]*1000+0.5)/1000.0 + ry;// 设置5的死区if(temp[0] <= 2005 && temp[0] >= 1995)temp[0] = 2000;if(temp[1] <= 2005 && temp[1] >= 1995)temp[1] = 2000;if(temp[2] <= 2005 && temp[2] >= 1995)temp[2] = 2000;if(temp[3] <= 2005 && temp[3] >= 1995)temp[3] = 2000;}//发送数据
void sendData(){// 数据位移senda[0] = (uint16_t)adc_value[0] >> 8;senda[1] = (uint16_t)adc_value[0];senda[2] = (uint16_t)adc_value[1] >> 8;senda[3] = (uint16_t)adc_value[1];senda[4] = (uint16_t)adc_value[2] >> 8;senda[5] = (uint16_t)adc_value[2];senda[6] = (uint16_t)adc_value[3] >> 8;senda[7] = (uint16_t)adc_value[3];// 按钮if(HAL_GPIO_ReadPin(GPIOB, KEY_B1_Pin) == 1){senda[8] = 1;}else{senda[8] = 0;}if(HAL_GPIO_ReadPin(GPIOB, KEY_B2_Pin) == 1){senda[8] += 2;}else{senda[8] += 0;}if(HAL_GPIO_ReadPin(GPIOB, KEY_B3_Pin) == 1){senda[8] += 4;}else{senda[8] += 0;}}// 定时器回调函数 如果没有进看看有没有开中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){if(htim == &htim1){Get_Data(adc_value,12);sendData();HAL_UART_Transmit_DMA(&huart2, senda, sizeof(senda) - 1); }
}

遥控器接收(在主控板上的配置新增)
HAL配置

全局变量

#define USART_DMA_TX_BUFFER_MAXIMUM          9    // DMA缓冲区大小
#define USART_DMA_RX_BUFFER_MAXIMUM         9    // DMA缓冲区大小int MotorOutput = 0;uint8_t usart1_rx_buffer[USART_DMA_RX_BUFFER_MAXIMUM]; //串口1的DMA接收缓冲区
uint8_t usart1_tx_buffer[USART_DMA_TX_BUFFER_MAXIMUM]; //串口1的DMA发送缓冲区
int x1 = 2000,x2 = 2000,y1 = 2000,y2 = 2000;
int count = 0;

添加方法

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart==&huart1){memcpy(usart1_tx_buffer,usart1_rx_buffer,9);//由于是异步的,发送和接收的buffer一定要分开。主程序不要随便修改这两个buffer的数据HAL_UART_Receive_DMA(huart,usart1_rx_buffer,9);//继续监听新的数据,Normal模式下发送和监听都是一次性的,
//这里可以根据需求动态调整下一次接收的帧长x1  = usart1_rx_buffer[0] << 8 | usart1_rx_buffer[1];y1  = usart1_rx_buffer[2] << 8 | usart1_rx_buffer[3];x2  = usart1_rx_buffer[4] << 8 | usart1_rx_buffer[5];y2  = usart1_rx_buffer[6] << 8 | usart1_rx_buffer[7];MotorOutput = -(x2-2000)/2;}}

底盘解算

对于全向轮的运动学结算网上有很多教程和例子讲的很好可以看看
三轮全向地盘要先确定轮子的序号和旋转方向 可以是如下

A转向C C转向B B转向A 为正向 以此为基础

添加方法 传入车的X方向 Y方向 Z方向(自转)的速度解析每个轮的速度

void Speed_Moto_Control(float vx,float vy,float vz)
{MotorB.set_speed   = (-VX_VALUE*vx + VY_VALUE*vy + L_value*vz);MotorC.set_speed   = (-VX_VALUE*vx - VY_VALUE*vy + L_value*vz);MotorA.set_speed   = (vx + L_value*vz);
}

效果视频

审核还没通过
QAQ

计划任务

改进代码 更换主控 实现速度的闭环控制
添加陀螺仪使其可以自转前进

三轮全向底盘小车制作 STM32主控 串口无线遥控器相关推荐

  1. 三轮全向底盘实现绘图功能

    1. 功能说明 本文示例将实现R313a样机三轮全向底盘绘图(三角形.矩形.三叶草.正弦曲线)的功能.三轮全向底盘绘制图形有两种模式:第一种是自主选择模式(即通过按下开关进行模式的选项):第二种是上位 ...

  2. 三轮全向底盘实现SLAM导航功能

    1. 功能说明 本文我们将利用键盘控制三轮全向底盘(R313b)小车运动完成slam建图,并能在已建好的地图里进行自主导航.slam导航可以拆分为三步: 第一步:能用键盘控制底盘的运动: 第二步:基于 ...

  3. STM32三轮全向底盘

    STM32三轮全向底盘 最近在实验室培训,玩过麦克纳姆四轮底盘后,玩三轮全向底盘也有一段时间了,于是来分享一下自己的心得. 附图 这是去年参加robocon的底盘,三个大疆3508电机,一个全场定位模 ...

  4. SLAM导航机器人零基础实战系列:(四)差分底盘设计——2.stm32主控软件设计

    SLAM导航机器人零基础实战系列:(四)差分底盘设计--2.stm32主控软件设计 摘要 运动底盘是移动机器人的重要组成部分,不像激光雷达.IMU.麦克风.音响.摄像头这些通用部件可以直接买到,很难买 ...

  5. 微信小程序控制三轮全向排爆小车

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.微信小程序制作 二.电机驱动 三.蓝牙串口通信 四.机械臂 前言 随着人工智能普及,智能小车开始流行起来,可是现在 ...

  6. 里程计模型(1):两轮差分底盘和三轮全向底盘

    两轮差分底盘运动学模型 目前使用最为广泛的底盘可以说就是两轮差分底盘,此类底盘具有结构简单.成本低.模型简单的特点. 1.差分底盘运动模型 差分底盘运动模型如图. 轮子到底盘中心的距离:ddd 底盘中 ...

  7. 三轮全向底盘:运动学性能分析

    速度分析 建立三轮底盘的速度物理学模型如图所示. 其中v1v_1v1​.v2v_2v2​.v3v_3v3​分别为三个轮子的转速,ωωω为旋转角速度,vxv_xvx​.vyv_yvy​为车身坐标系中的速 ...

  8. [基于STM32底盘控制与ROS上层导航小车制作] 第五节 实现STM32与ubuntu系统下的ROS串口DMA通信,传输底盘速度等信息

    系列文章目录 第一节 stm32电机驱动与编码器读取反馈 第二节 stm32电机pid控制 第三节 stm32线速度标定 第四节 stm32添加mpu6050得到angle角度 第五节 实现STM32 ...

  9. Arduino三轮全向小车(一):编码马达的使用

    Arduino三轮全向小车(一):编码马达的使用## 标题 近期准备做一个arduino作为下位机的底盘,看了很多,还是不知所以然,干脆直接开始动手,变搞边学习.然而查阅网上各种资料高深莫测,看得我云 ...

最新文章

  1. vue 动态添加class_前端开发:Vue项目实战-Music
  2. 【Linux网络编程】组播
  3. WEB接口测试之Jmeter接口测试自动化 (四)(持续构建)
  4. 【转】GitHub上README.md教程
  5. c++语言怎么从internet上某个时间服务器获取时间信息,在VC++中实现同步Internet时间...
  6. 【Flink】kafka Response from server for which there are no in-flight requests NETWORK_EXCEPTION
  7. c语言速算24源代码,C语言源程序代码-速算24
  8. 使用/调用 函数的时候, 前面加不加 对象或 this?
  9. 面向对象之多态、多态性
  10. Mysql数据备份与mysqldump增量备份
  11. sca60c使用程序_使用PHP的SDO和SCA扩展
  12. 由系统函数求零极点图、频率响应(幅频特性、相频特性)的 Matlab 和 Python 方法
  13. Rainmeter,让你的桌面更精彩~
  14. 五种百度云盘下载速度慢解决方法
  15. 域名在国外注册的服务器能查到吗,对于国外域名查询,你还需要知道这些!
  16. uniApp微信小程序获取当前用户手机号码(前端)
  17. 黑马程序员——Java基础--IO流(一)---File类以及其他流对象
  18. LCD2864 T 串行通信 STM32 MSP430 单片机 显示屏 显示测试程序
  19. github热门java项目_盘点Github上热门的Java开源项目
  20. Chem 3D软件可以改变背景吗

热门文章

  1. 物理CPU (physical CPU)、 逻辑CPU(logical CPU)、虚拟CPU(virtual CPU)、核数(core)、线程数(thread)、颗数(socket)
  2. 小字辈(c/c++)本题给定一个庞大家族的家谱,要请你给出最小一辈的名单。
  3. 假如AIphago五战全胜李世石
  4. vue-particles-很棒的粒子特效的插件,就是有点那啥...
  5. Appstore 检查 appleid
  6. TOM企业电子邮箱注册,你的域名邮箱设置电子名片了吗?
  7. legendmatlab_matlab legend 使用
  8. FCM模糊C均值聚类分析(Fuzzy C-means)公式推导与MATLAB程序
  9. Python爬虫之利用requests,BeautifulSoup爬取小说标题、章节
  10. 国产高性价比手机要凉凉?官方回应