Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

MengFanjun的博客

最近买了个平衡小车,为了圆我PID梦,买来玩玩,废话不多说,直接开搞

第一步:让小车的轮子转起来

我用的电机是TB6612FNG,想详细了解的话直接去搜手册,给他输出两路PWM还要两个引脚进行高低电平的转换就可以设置前进或者后退了,规则如下 在这里插入图片描述 看一下引脚图吧 在这里插入图片描述 引脚连接:

PWMA PA11
PWMB PA8
AIN1 PB13
AIN2 PB12
BIN1 PB14
BIN2 PB15

下面开始配置CUBE 首先是SYS: 在这里插入图片描述 其次是时钟: 在这里插入图片描述 在这里插入图片描述

下面开始引脚的设置: 在这里插入图片描述 用定时器1,10Hz就够了 在这里插入图片描述 生成: 在这里插入图片描述

代码部分: main.h

1
2
3
4
5
6
7
8
9
10
11
/* USER CODE BEGIN Private defines */
#define AIN2_Pin GPIO_PIN_12
#define AIN2_GPIO_Port GPIOB
#define AIN1_Pin GPIO_PIN_13
#define AIN1_GPIO_Port GPIOB

#define BIN2_Pin GPIO_PIN_14
#define BIN2_GPIO_Port GPIOB
#define BIN1_Pin GPIO_PIN_15
#define BIN1_GPIO_Port GPIOB
/* USER CODE END Private defines */

main.c

1
2
3
4
5
6
7
8
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//开启TIM1_CH1
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);//开启TIM1_CH4
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_RESET);//AIN1为0
HAL_GPIO_WritePin(AIN2_GPIO_Port,AIN2_Pin,GPIO_PIN_SET);//AIN2位1,反转
HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_RESET);//BIN1为0
HAL_GPIO_WritePin(BIN2_GPIO_Port,BIN2_Pin,GPIO_PIN_SET);//BIN2位1,反转
/* USER CODE END 2 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AIN2_GPIO_Port,AIN2_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(BIN1_GPIO_Port,BIN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(BIN2_GPIO_Port,BIN2_Pin,GPIO_PIN_SET);
for(int i=0;i<7100;i++)
{
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_4,i);//让轮子转起来
HAL_Delay(1);
}
for(int j=7100;j>0;j--)
{
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_4,j);
HAL_Delay(1);
}
for(int i=0;i<7100;i++)
{
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,i);
HAL_Delay(1);
}
for(int j=7100;j>0;j--)
{
__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,j);
HAL_Delay(1);
}
}
/* USER CODE END 3 */

第二步:用编码器测出小车的速度

先看原理图 在这里插入图片描述 PA0和PA1,PA6和PA7分别是小车的编码器引脚,所以我们在cunbe中将这四个引脚设置为Encoder模式 在这里插入图片描述 在cube中设置好编码器之后,我们再设置好串口,异步通信,再打开中断 在这里插入图片描述 首先开启编码器

1
2
3
4
5
6
7
8
9
10
11
12
void Encoder_Start(void)   //启动两个编码器. 而编码器初始化HAL_TIM_Encoder_Init()和HAL_TIM_Encoder_MspInit()在main()函数中调用的MX_TIM2_Init()中。
{
__HAL_TIM_SET_COUNTER(&htim2,0); //用带参宏设置编码器的初始值为0(涉及正反转的需要)
__HAL_TIM_SET_COUNTER(&htim3,0);

HAL_TIM_Encoder_Start_IT(&htim2,TIM_CHANNEL_ALL); //开启编码器的中断模式,两个定时器通道TI1和TI2是每个编码器的两个信号采集通道.
HAL_TIM_Encoder_Start_IT(&htim3,TIM_CHANNEL_ALL);

HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL); //开启两个编码器
HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);

}

读取编码器速度值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int Read_Speed(int TIMx)
{
int Encoder_Value = 0;
switch(TIMx)
{
case 2:
Encoder_Value =(short) __HAL_TIM_GET_COUNTER(&htim2); //保存编码器计数器的值
__HAL_TIM_SET_COUNTER(&htim2,0); //保存之后要清零,以便下次继续读取.另外每次清零后采样值减0,直接用单位时间的话就可以得出速度信息了.不要麻烦还要减去初值了.
break;

case 3:
Encoder_Value =(short) __HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COUNTER(&htim3,0);
break;

default:
Encoder_Value = 0;
}
return Encoder_Value;
}

这里是主函数,记得定义encoder2和encoder3

1
2
3
4
5
6
7
8
9
10
  /* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
encoder2=Read_Speed(2);
encoder3=Read_Speed(3);
printf("A轮=%d,B轮=%d\n",encoder2,encoder3);
}
}
输出结果,因为是拿手转的,只能一只手转轮子: 在这里插入图片描述

第三步:读取MPU6050的数据值

接下来就是最难的MPU6050了,我这里就不详细讲了,因为我自己对底层也不是很了解

左边我们可以看到XYZ的加速度,和XYZ陀螺仪数值,他们经过ADC转换后的数值通过IIC可以直接输出,但是数值就是纯数值,并不是角度值,然后就去DMP了,DMP在输出去FIMO,我理解就是,可以把MPU6050读取的这些东西,变成四元数,然后再通过IIC输出,就可以变成角度值了

在这里插入图片描述 首先我们在CUBE中配置好IIC的SDA线和SCL线 在这里插入图片描述 在这里插入图片描述 MPU6050的读写程序我就不展示了,因为这些从网络上都能找到,我用的是正点原子的,需要注意的就是我这里用的是硬件的HAL库IIC,之前我们老师说硬件的IIC有点bug,让我们用软件的,但是我试了试硬件的IIC,发现也挺好用的,就不用软件的了

读取结果: 在这里插入图片描述 可以看到欧拉角的角度值,这样就可以去调整小车的姿态了

第四步:PID

最近在做智能采摘机器人 有时间一定接着更!

评论