技术日志——第五篇

这篇技术日志的前一小部分是昨天做的的,可能会有一些遗忘的地方。就不过多的写了。上一篇提到了一个很重要的问题就是,线路非常难接,所以我焊接了一个临时的电路板,依旧是有很多的飞线,但是目前还没有办法,要等回学校再考虑pcb的问题

焊接临时电路板

临时电路板要完成两个任务:电机排线的连接和电压转换
电机的接口处用杜邦线临时连接非常的不稳定,还是要用排线引到电路板上,再连接杜邦线
另外还有很多需要5V电压的模块,于是接了一个电压转换模块,当显示器里的电压是4.8V时,实际测的电压已经到了5V,于是就按4.8V来。

这样整体焊接完之后就感觉还可以接受了:
在这里插入图片描述

问题

问题很简单,直流电机的通病,每个电机的转速不一样。我昨天焊接好并且接好线之后做了陀螺仪的自动校准测试,在高速情况下还可以,但是微调的时候有些电机就不转了,这个时候不同电机的电机特性差异就比较明显了

所以我的建议还是把之前没加的编码器加上

编码器

编码器又要重新接线,今天一步一步的记录。
1.四个编码器需要四个电源接口,昨天焊接的板子5V接口全部用完了,于是又焊接了几个引脚,简单的扩展了一下:
在这里插入图片描述
还是有一些变化的。

2.第二步,老花样,做并线= =
四根并线都做好了并且接上了,编码器的电源和地线都是一分四
在这里插入图片描述

配置CubeMx

之前的文章解释过为何要使用外部中断来触发,主要原因就是定时器接口不够用了,四个编码器,因为无需判断方向,所以只接四个外部中断接口,

选择四个引脚作为外部中断引脚,上拉:
在这里插入图片描述

开启中断:
在这里插入图片描述

设置一下以前一直都没有设置过的中断优先级:
在这里插入图片描述
生成代码后可以在这里看到回调函数:
在这里插入图片描述

弱符号中断回调函数(例子):

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    HAL_Delay(10);
    switch(GPIO_Pin){
        case GPIO_PIN_0:
            HAL_GPIO_WritePin(GPIOB,BUZ_Pin,GPIO_PIN_SET);
            HAL_Delay(300);
            HAL_GPIO_WritePin(GPIOB,BUZ_Pin,GPIO_PIN_RESET);
            HAL_Delay(300);
            break;
        case GPIO_PIN_2:
            HAL_GPIO_TogglePin(GPIOC,LED1_Pin);
            break;
        case GPIO_PIN_3:
            HAL_GPIO_TogglePin(GPIOC,LED2_Pin);
            break;
        case GPIO_PIN_4:
            HAL_GPIO_TogglePin(GPIOC,LED1_Pin);
            HAL_GPIO_TogglePin(GPIOC,LED2_Pin);
            break;
    }
}

引脚对应表

改引脚对应表已在第一篇技术日志更新

	A电机  
    A相    ------------   PE1
	
	B电机  
    A相    ------------   PE2
    
    C电机  
    A相    ------------   PE3
    
    D电机  
    A相    ------------   PE0

编码器获得速度程序

首先是定义变量:

uint32_t Count1=0,Count2=0,Count3=0,Count4=0;
float readV1,realV2,realV3,realV4;

更改回调函数:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    switch(GPIO_Pin){
        case GPIO_PIN_1:
            Count1++;
            break;
        case GPIO_PIN_2:
            Count2++;
            break;
        case GPIO_PIN_3:
            Count3++;
            break;
        case GPIO_PIN_0:
            Count4++;
            break;
    }
}

在这里插入图片描述
电机每转一圈,输出390个脉冲,dt的单位是毫秒,故乘以一千,可以得到真实的速度,代码里最终的单位是r/min,更改定时器中断函数如下:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		lastsysclock=sysclock;
		sysclock = HAL_GetTick();//返回从系统运行开始经过的时间,默认情况下单位为ms
		dt=sysclock-lastsysclock;

		realV1=((1000*60)/(390*dt))*Count1;//电机每转一圈,输出390个脉冲,dt的单位是毫秒,故乘以一千,最终的单位是r/min
		realV2=((1000*60)/(390*dt))*Count2;
		realV3=((1000*60)/(390*dt))*Count3;
		realV4=((1000*60)/(390*dt))*Count4;
		printf("rV1=%.2f , rV2=%.2f , rV3=%.2f , rV4=%.2f\r\n",realV1,realV2,realV3,realV4);
		Count1=0;
		Count2=0;
		Count3=0;
		Count4=0;
		//Calculate_angular_velocity();
		//Calculated_combined_velocity();
	}
}

空载电机特性测试

空载情况下的测试电机的最低转速对应的占空比全部开通时电机的转速
1.全部开通时的转速
在这里插入图片描述
2.最低转速和对应的占空比
占空比如下:

	V1=41;
	V2=43;
	V3=39;
	V4=42;

此时对应的速度如下:
在这里插入图片描述

速度控制程序

添加上编码器,我的主要目的是可以对电机的实际转速进行控制

对此我暂且想了一个办法,是否有效要经过测试:
从门槛pwm占空比到满占空比之间,转速和占空比接近线性,那么对于每一个电机来讲都有一条占空比——转速曲线,我已经测出来了两个端点,那么可以得出来这条曲线的方程。
每次设定速度的时候都有一个目标速度,然后根据直线方程可以得到一个近似的占空比,让小车根据这个占空比进行旋转,如果测得的实际速度和目标速度有差异,就相应的更改占空比。

计算四个电机的占空比——转速曲线

K1=(315-69)/(100-41)=4.17
K2=(309-57)/(100-43)=4.42
K3=(309-54)/(100-39)=4.18
K4=(303-48)/(100-42)=4.40

故可解得:
y1=4.17x1-102
y2=4.42x2-133
y3=4.18x3-109
y4=4.40x4-137

反解x:
x1=(y1+102)/4.17
x2=(y2+133)/4.42
x3=(y3+109)/4.18
x4=(y4+137)/4.40

其中x是占空比,y是速度

程序部分

首先定义几个新变量:
moto.c:

float PWM1=0,PWM2=0,PWM3=0,PWM4=0;
extern float realV1,realV2,realV3,realV4;

main.c:

float target_V1,target_V2,target_V3,target_V4;

extern float PWM1,PWM2,PWM3,PWM4;

在moto.c添加新函数:

void set_velocity(int moto,float target_speed)
{
	if(moto==1)
	{
		if(motor_custom_abs(motor_custom_abs(realV1)-motor_custom_abs(target_speed))>30)	PWM1=(motor_custom_abs(target_speed)+102)/4.17f;
		if(target_speed>=0)
		{
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_3, 0);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, PWM1);    //修改比较值,修改占空比pwm2/7200
		}
		if(target_speed<0)
		{
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_3, -PWM1);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 0);    //修改比较值,修改占空比pwm2/7200
		}
	}
	
	if(moto==2)
	{
		if(motor_custom_abs(motor_custom_abs(realV2)-motor_custom_abs(target_speed))>30)	PWM2=(motor_custom_abs(target_speed)+133)/4.42f;
		if(target_speed>=0)
		{
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, PWM2);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 0);    //修改比较值,修改占空比pwm2/7200
		}
		if(target_speed<0)
		{
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, 0);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, -PWM2);    //修改比较值,修改占空比pwm2/7200
		}

	}
	
	if(moto==3)
	{
		if(motor_custom_abs(motor_custom_abs(realV3)-motor_custom_abs(target_speed))>30)	PWM3=(motor_custom_abs(target_speed)+109)/4.18f;
		if(target_speed>=0)
		{
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_1, 0);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_2, PWM3);    //修改比较值,修改占空比pwm2/7200
		}
		if(target_speed<0)
		{
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_1, -PWM3);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_2, 0);    //修改比较值,修改占空比pwm2/7200
		}

	}
	
	if(moto==4)
	{
		if(motor_custom_abs(motor_custom_abs(realV4)-motor_custom_abs(target_speed))>30)	PWM4=(motor_custom_abs(target_speed)+137)/4.40f;
		if(target_speed>=0)
		{
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, 0);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, PWM4);    //修改比较值,修改占空比pwm2/7200
		}
		if(target_speed<0)
		{
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, -PWM4);    //修改比较值,修改占空比pwm1/7200
			__HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 0);    //修改比较值,修改占空比pwm2/7200
		}
	}
	
}

这个函数的意思是,如果实际速度和目标速度差别超过了30,就会根据直线公式计算得到的PWM值来输出

main.c里:

float main_abs(float target)//不知道为何无法使用abs,自己写个abs
{
	if (target>=0)	return target;
	else return -target;
}

定时中断里:

if(realV1>main_abs(target_V1))	PWM1--;
else	PWM1++;
if(realV2>main_abs(target_V2))	PWM2--;
else	PWM2++;
if(realV3>main_abs(target_V3))	PWM3--;
else	PWM3++;
if(realV4>main_abs(target_V4))	PWM4--;
else	PWM4++;

上面函数的意思是,如果测出来的实际速度与目标的速度不符合了,会进行补偿调整

在while里设置好目标速度,并且调用moto.c里刚写好的set_velocity

  while (1)
  {
		target_V1=20;
		target_V2=100;
		target_V3=200;
		target_V4=300;
		set_velocity(1,target_V1);
		set_velocity(2,target_V2);
		set_velocity(3,target_V3);
		set_velocity(4,target_V4);

烧录程序,测试
在这里插入图片描述
可以看出来,在速度非常低,比如V1的目标速度是20,会有比较大的波动,这个是正常的,因为按照以前来讲,根本无法实现20这么低的速度,但是现在可以做到了,不过我看了过程,获得20速度的过程较长。
速度起来后,基本上很快就能稳定。

成功!

总结

目前使用了编码器,并且可以获得大概50-300之间的空载速度,而且是准确的。也就是说可以直接对速度进行控制。

下一步任务:

  • 完成陀螺仪校准程序
  • 完成激光测距定位程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值