工程来自野火电机程序包,有需要可自行下载
野火下载
程序流程
代码解读
mian.c中的函数,各种初始化,之后在while(1)里面的函数,下面括号代表函数定义所在板级支持包
- 接受上位机数据(protocol.c)
receiving_process();
- 扫码按键按下或者处理上位机数据(key.c protocol.c)
- 实现功能例如使能电机,停止电机,加减速电机速度(motor_control.c)
led.c和key.c就不讲了,很基础。
下图是位置式PID在实际运行中的过程分析
过程部分代码详解
1.首先是基本定时器定时产生更新,对时钟6产生时钟周期,每50ms产生一次溢出,这个周期的选择只要比采样周期大就行。 basic_tim.c文件对定时器进行初始化并且产生更新中断。 可参照我的文章,笔记中有介绍。
2.更新产生后进入中断,中断进入回调函数,回调函数中记录了编码器计时器溢出次数,调用了电机pid控制函数。
/**
* @brief 定时器更新事件回调函数
* @param 无
* @retval 无
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//如果是编码器产生中断信号,判断计数器方向并记录溢出次数
if(htim==(&TIM_EncoderHandle))
{
/* 判断当前计数器计数方向 */
if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&TIM_EncoderHandle))
/* 下溢 */
Encoder_Overflow_Count--;
else
/* 上溢 */
Encoder_Overflow_Count++;
}
//如果基础定时器产生中断,调用电机PID控制函数
else if(htim==(&TIM_TimeBaseStructure))
{
motor_pid_control();
}
}
编码器encode.c采用tim3,使用输入捕获模式,4倍频,最大计数,可参考我的文章。
3.motor_pid_control函数讲解
/**
* @brief 电机位置式 PID 控制实现(定时调用)
* @param 无
* @retval 无
*/
void motor_pid_control(void)
{
if (is_motor_en == 1) // 电机在使能状态下才进行控制处理
{
float cont_val = 0; // 当前控制值
static __IO int32_t Capture_Count = 0; // 当前时刻总计数值
static __IO int32_t Last_Count = 0; // 上一时刻总计数值
int32_t actual_speed = 0; // 实际测得速度
/* 当前时刻总计数值 = 计数器值 + 计数溢出次数 * ENCODER_TIM_PERIOD */
Capture_Count =__HAL_TIM_GET_COUNTER(&TIM_EncoderHandle) + (Encoder_Overflow_Count * ENCODER_TIM_PERIOD);
/* 转轴转速 = 单位时间内的计数值 / 编码器总分辨率 * 时间系数 */
//总计数除以每圈计数就是转了多少圈,再除以减速比等于实际主轴的转的圈数,再除以定时器的周期,以分为单位,就是每分钟转多少圈
actual_speed = ((float)(Capture_Count - Last_Count) / ENCODER_TOTAL_RESOLUTION / REDUCTION_RATIO) / GET_BASIC_TIM_PERIOD()/1000.0/60.0);
/* 记录当前总计数值,供下一时刻计算使用 */
Last_Count = Capture_Count;
cont_val = PID_realize(actual_speed); // 进行 PID 计算
if (cont_val > 0) // 判断电机方向,再根据方向和pid返回的值进行控制
{
set_motor_direction(MOTOR_FWD);
}
else
{
cont_val = -cont_val;
set_motor_direction(MOTOR_REV);
}
cont_val = (cont_val > PWM_MAX_PERIOD_COUNT) ? PWM_MAX_PERIOD_COUNT : cont_val; // 速度上限处理
set_motor_speed(cont_val); // 设置 PWM 占空比
#if defined(PID_ASSISTANT_EN)
set_computer_value(SEND_FACT_CMD, CURVES_CH1, &actual_speed, 1); // 给通道 1 发送实际值
#else
printf("实际值:%d. 目标值:%.0f\n", actual_speed, get_pid_target()); // 打印实际值和目标值
#endif
}
}
关于PID的计算我会再出一篇文章。
motor_control.c中还写了关于电机使能,关闭,加减速的一些操作,这些操作都是控制pwm波的输出,之前的文章也写过。
motor_tim.c文件里面是pwm波初始化文件
usart.c文件初始化串口通信,用于打印信息
protocol.c野火PID调试助手通讯协议解析,这部分还不会回头补充