前言 --末尾右总体的.c和.h
本篇文章把麦克纳姆轮的代码封装到.c和.h,使用者只需要根据轮子正转的方向,在.h处修改定义方向引脚,把轮子都统一正向后,后面的轮子驱动就可以正常了,然后直接调用函数驱动即可。
设置满转预充装载值是1000
其中会有几种方案
第一种是直接开环,没有任何返款
第二种是编码行走,开环走到指定位置,容易收重力导致走歪
第三种是陀螺仪行走,有陀螺仪闭环防止走歪
第四种是编码陀螺仪,是第二种的升级版,走到指定距离且不歪
头文件处的定义内容讲解
我们先看.h,知道哪些函数会有哪些功能和宏定义参数
1.方向引脚,定时器引脚,编码中断引脚定义
首先 是在.h的宏定义处定义引脚编号,比如tb6612控制方向的引脚,以及设定了哪个定时器作为pwm输出,还有编码计次的中断引脚
/* 硬件相关宏定义 *//*
1 前进方向往上 42 3
*/
// TB6612 方向引脚定义
#define MOTOR1_PIN_A_PORT GPIOA
#define MOTOR1_PIN_A_PIN (1 << 8)
#define MOTOR1_PIN_B_PORT GPIOC
#define MOTOR1_PIN_B_PIN (1 << 9)#define MOTOR2_PIN_A_PORT GPIOC
#define MOTOR2_PIN_A_PIN (1 << 8)
#define MOTOR2_PIN_B_PORT GPIOD
#define MOTOR2_PIN_B_PIN (1 << 13)#define MOTOR3_PIN_A_PORT GPIOD
#define MOTOR3_PIN_A_PIN (1 << 9)
#define MOTOR3_PIN_B_PORT GPIOD
#define MOTOR3_PIN_B_PIN (1 << 10)#define MOTOR4_PIN_A_PORT GPIOD
#define MOTOR4_PIN_A_PIN (1 << 11)
#define MOTOR4_PIN_B_PORT GPIOD
#define MOTOR4_PIN_B_PIN (1 << 12)/* 定时器相关宏定义 */
#define PWM_TIMER &htim1
#define PWM_CHANNEL_1 TIM_CHANNEL_1
#define PWM_CHANNEL_2 TIM_CHANNEL_2
#define PWM_CHANNEL_3 TIM_CHANNEL_3
#define PWM_CHANNEL_4 TIM_CHANNEL_4/* 编码器相关宏定义 */
#define ENCODER_CHA_1_PIN GPIO_PIN_4
#define ENCODER_CHA_1_PORT GPIOA
#define ENCODER_CHA_2_PIN GPIO_PIN_2
#define ENCODER_CHA_2_PORT GPIOB
#define ENCODER_CHA_3_PIN GPIO_PIN_6
#define ENCODER_CHA_3_PORT GPIOE
#define ENCODER_CHA_4_PIN GPIO_PIN_12
#define ENCODER_CHA_4_PORT GPIOE
把自己的引脚根据原理图填对应,方向引脚也是,如果发现反转就把对应的引脚定义反过来,编码也是,编码我们用一个引脚就好,都在cubemx配置好。
2.参数定义
/* 控制参数相关宏定义 */
// 速度控制参数
#define MIN_ROTATION_DUTY_CYCLE 100
#define ROTATION_SPEED 300// PD控制器参数
#define BACK_KP 10 // 后退PD参数
#define BACK_KD 0
#define STRAIGHT_KP 10 // 直行PD参数
#define STRAIGHT_KD 0
#define LEFT_KP 30 // 横向左转PD参数
#define LEFT_KD 0
#define RIGHT_KP 30 // 横向右转PD参数
#define RIGHT_KD 0
#define ROTATE_KP 5 // 旋转PD参数
#define ROTATE_KD 0.2// 陀螺仪配置
#define GYRO_POLARITY 0 /* 类型定义 */
typedef struct {float kp; // 比例系数float kd; // 微分系数float prev_error; // 上一次误差
} PDController;
这里的话包括,第一个是自旋转的时候,最小的旋转占空比,还有正常旋转占空比。
然后是配合上陀螺仪时候的PID各个功能参数
还有一个是陀螺仪极性,调用函数后发现是往相反方向移动,那么就修改这个值,因为陀螺仪正放和倒放的极性不同,0和1代表不同的极性。可以观察使用测试程序后,如果发现旋转后离目标点越来越大,那就修改极性。
一 功能函数的定义
后面会用到这么多函数,其中包括
1.基本开环函数
这里的函数就是不带反馈的,给占空比值就动,会容易收到重力分布不均影响,导致走歪。
2.距离开环函数
这里的函数根据给定要跑的距离,跑到后停止,距离由uint16_t wheel_get_count(void);函数返回,但是跑的过程中可能会因为重力分布不均影响,导致走歪。
3.带陀螺仪的闭环函数
这里的函数通过传入标准值,然后方向会以标准值作为参考调制轮子占空比,从而防止走偏。不过使用的时候要在循环里面使用,因为只调用一次肯定是行不通的。
4.带编码的陀螺仪闭环函数
这个根据陀螺仪的值防止走偏,然后由根据编码值确定要走的距离,最为精准。
/* 函数声明 */
// 初始化函数
void wheel_init(void);
void wheel_begin_go(void);// 基础控制函数
void wheel_stop(void);
void set_all_pwm_channels(uint16_t speed);
void set_all_pwm_channels_separate(uint16_t speed1, uint16_t speed2, uint16_t speed3, uint16_t speed4);
void tb6612_set_direction(uint8_t motor_num, uint8_t polarity);// 闭环控制函数
void wheel_go_back(uint16_t now_z, uint16_t speed);
// 修改函数名
void wheel_go_forward(uint16_t now_z, uint16_t speed);
void wheel_go_right(uint16_t now_z, uint16_t speed);
void wheel_go_left(uint16_t now_z, uint16_t speed);
void wheel_rotate(int16_t angle);// 开环控制函数
void wheel_go_forward_openloop(uint16_t speed);
void wheel_go_back_openloop(uint16_t speed);
void wheel_go_left_openloop(uint16_t speed);
void wheel_go_right_openloop(uint16_t speed);
void wheel_rotate_left_openloop(uint16_t speed);
void wheel_rotate_right_openloop(uint16_t speed);// 带编码器的闭环控制函数
// 修改函数名
void wheel_go_forward_count_close(uint16_t count, uint16_t speed);
void wheel_go_back_count_close(uint16_t count, uint16_t speed);
void wheel_go_left_count_close(uint16_t count, uint16_t speed);
void wheel_go_right_count_close(uint16_t count, uint16_t speed);// 带编码器的开环控制函数
void wheel_go_forward_count_open(uint16_t count, uint16_t speed);
void wheel_go_back_count_open(uint16_t count, uint16_t speed);
void wheel_go_left_count_open(uint16_t count, uint16_t speed);
void wheel_go_right_count_open(uint16_t count, uint16_t speed);// 辅助函数
uint16_t clamp_speed(uint16_t speed, uint16_t error);
uint16_t get_angle_value(void);
uint16_t wheel_get_count(void);
int32_t count_save(uint8_t cmd);
void wheel_polarity_test(void);#endif // WHEEL_H
二.辅助函数的介绍
有一些算法需要功能函数
1.过冲函数
我们使用陀螺仪配合的时候,万一根据差值相减后给的占空比小于0,因为是无符号整型,此时是无穷大的,这时候的占空比会拉满,导致过冲现象。
/*** @brief 确保计算后的速度不小于0* @param speed 当前速度值* @param error 误差值* @return 调整后的速度值*/
uint16_t clamp_speed(uint16_t speed, uint16_t error) {if (speed > error) {return speed - error;}return 0;
}/*** @brief 限制速度在合理范围* @param speed 当前速度值* @param max_speed 最大速度限制* @return 调整后的速度值*/
uint16_t limit_speed(uint16_t speed, uint16_t max_speed) {if (speed > max_speed) {return max_speed;}return speed;
}
2. 设置占空比函数
两个函数,一个设置全部占空比,一个分别设置占空比
/*** @brief 设置四个通道PWM占空比(相同值)* @param speed PWM占空比值*/
void set_all_pwm_channels(uint16_t speed) {__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_1, speed);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_2, speed);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_3, speed);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_4, speed);
}/*** @brief 设置四个通道PWM占空比(不同值)* @param speed1 通道1PWM值* @param speed2 通道2PWM值* @param speed3 通道3PWM值* @param speed4 通道4PWM值*/
void set_all_pwm_channels_separate(uint16_t speed1, uint16_t speed2, uint16_t speed3, uint16_t speed4) {__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_1, speed1);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_2, speed2);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_3, speed3);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_4, speed4);
}
3.TB6612方向确认及初始化函数
这里主要是让引脚定义规范,基本上默认1就是正转
然后还有初始化和停车的函数
/*** @brief 控制TB6612电机方向* @param motor_num 电机编号(1-4)* @param polarity 方向(0或1)*/
void tb6612_set_direction(uint8_t motor_num, uint8_t polarity) {switch (motor_num) {case 1:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR1_PIN_A_PORT, MOTOR1_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR1_PIN_B_PORT, MOTOR1_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR1_PIN_A_PORT, MOTOR1_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR1_PIN_B_PORT, MOTOR1_PIN_B_PIN, 1);}break;case 2:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR2_PIN_A_PORT, MOTOR2_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR2_PIN_B_PORT, MOTOR2_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR2_PIN_A_PORT, MOTOR2_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR2_PIN_B_PORT, MOTOR2_PIN_B_PIN, 1);}break;case 3:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR3_PIN_A_PORT, MOTOR3_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR3_PIN_B_PORT, MOTOR3_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR3_PIN_A_PORT, MOTOR3_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR3_PIN_B_PORT, MOTOR3_PIN_B_PIN, 1);}break;case 4:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR4_PIN_A_PORT, MOTOR4_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR4_PIN_B_PORT, MOTOR4_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR4_PIN_A_PORT, MOTOR4_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR4_PIN_B_PORT, MOTOR4_PIN_B_PIN, 1);}break;default:break;}
}/*** @brief 初始化轮子控制模块*/void wheel_init() {HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); set_all_pwm_channels(0);}/*** @brief 停止所有轮子*/void wheel_stop() {set_all_pwm_channels(0);}
4.编码计次及陀螺仪函数
每次启动前可以用wheel_begin_go()函数清零看,走的过程中可以用 wheel_get_count()返回数值,get_angle_value()函数里,修改成你返回z轴角度值的函数 ,修改成这样调用方便,要不然定义的函数不一样要修改的太多了。
/*** @brief 开始运动,重置编码器计数*/
void wheel_begin_go()
{count_save(8);
}/*** @brief 获取编码器平均计数* @return 四个编码器的平均计数值*/
uint16_t wheel_get_count()
{return (count_save(4)+count_save(5)+count_save(6)+count_save(7))/4;
}/*** @brief 编码器计数保存与读取函数* @param cmd 命令码,0-3 为计数加 1,4-7 为读取计数,8 为重置计数* @return 根据命令码返回相应计数值,无返回值命令返回 0*/
int32_t count_save(uint8_t cmd)
{static int32_t count[4]={0};if(cmd<4){count[cmd]++;}else if(cmd<8){return count[cmd-4];}else if(cmd==8){for(uint8_t i=0;i<4;i++)count[i]=0;}return 0;
}/*** @brief GPIO 外部中断回调函数* @param GPIO_Pin 触发中断的 GPIO 引脚*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {switch (GPIO_Pin) {case ENCODER_CHA_1_PIN:count_save(0);break;case ENCODER_CHA_2_PIN:count_save(1);break;case ENCODER_CHA_3_PIN:count_save(2);break;case ENCODER_CHA_4_PIN:count_save(3);break;default:break;}__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}/*** @brief 获取当前角度值* @return 当前角度值,调用 get_xyz_z 函数获取*/
uint16_t get_angle_value()
{return (uint16_t)get_xyz_z();
}
5.防陀螺仪角度突变函数
我们的目标角度是355度,但是当前是5度,我们应该是往0处突变成359,而不是旋转一周,所以需要旋转突变辅助。
/*** @brief 计算角度差值* @param target 目标角度* @param current 当前角度* @return 角度差值*/
int16_t calculate_angle_diff(uint16_t target, uint16_t current) {int16_t diff = (int16_t)(target - current);diff = (diff + 180) % 360;if (diff < 0) {diff += 360;}diff -= 180;
#if GYRO_POLARITY == 0diff = -diff;
#endifreturn diff;
}
三.功能函数
1.基本开环函数
(1)前进
/*** @brief 开环前进* @param speed 目标速度*/
void wheel_go_forward_openloop(uint16_t speed) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);set_all_pwm_channels(speed);
}
(2)后退
/*** @brief 开环后退* @param speed 目标速度*/
void wheel_go_back_openloop(uint16_t speed) {tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);set_all_pwm_channels(speed);
}
(3)左移
/*** @brief 开环左移* @param speed 目标速度*/
void wheel_go_left_openloop(uint16_t speed) {tb6612_set_direction(1, 1);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 1);set_all_pwm_channels(speed);
}
(4)右移
/*** @brief 开环右移* @param speed 目标速度*/
void wheel_go_right_openloop(uint16_t speed) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 0);set_all_pwm_channels(speed);
}
(5)自旋转往左
/*** @brief 开环左转* @param speed 目标速度*/
void wheel_rotate_left_openloop(uint16_t speed) {tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);set_all_pwm_channels(speed);
}
(6)自旋转向右
/*** @brief 开环右转* @param speed 目标速度*/
void wheel_rotate_right_openloop(uint16_t speed) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);set_all_pwm_channels(speed);
}
2.带编码的开环函数
这个直接走指定距离
(1)前进
/*** @brief 带编码器开环前进* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_forward_count_open(uint16_t count, uint16_t speed)
{// 重置编码器计数wheel_begin_go();// 等待直到编码器计数达到目标值while (wheel_get_count() < count) {wheel_go_forward_openloop(speed);}// 停止电机set_all_pwm_channels(0);
}
(2)后退
/*** @brief 带编码器开环后退* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_back_count_open(uint16_t count, uint16_t speed) {wheel_begin_go();while (wheel_get_count() < count) {wheel_go_back_openloop(speed);}set_all_pwm_channels(0);
}
(3)左移
/*** @brief 带编码器开环左移* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_left_count_open(uint16_t count, uint16_t speed) {wheel_begin_go();while (wheel_get_count() < count) {wheel_go_left_openloop(speed);}set_all_pwm_channels(0);
}
(4)右移
/*** @brief 带编码器开环右移* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_right_count_open(uint16_t count, uint16_t speed) {wheel_begin_go();while (wheel_get_count() < count) {wheel_go_right_openloop(speed);}set_all_pwm_channels(0);
}
3.陀螺仪闭环函数
这种是根据陀螺仪变化的,需要在while()里执行
(1)前进
/*** @brief 直行控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_forward(uint16_t now_z, uint16_t speed) {PDController pd = {STRAIGHT_KP, STRAIGHT_KD, 0};tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}
(2)后退
/*** @brief 后退控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_back(uint16_t now_z, uint16_t speed) {PDController pd = {BACK_KP, BACK_KD, 0};tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}
(3)左移
/*** @brief 左移控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_left(uint16_t now_z, uint16_t speed) {PDController pd = {LEFT_KP, LEFT_KD, 0};tb6612_set_direction(1, 1);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 1);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}
(4)右移
/*** @brief 右移控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_right(uint16_t now_z, uint16_t speed) {PDController pd = {RIGHT_KP, RIGHT_KD, 0};tb6612_set_direction(1, 0);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 0);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}
(5)自旋转
其中左转为正
/*** @brief 旋转控制(带陀螺仪闭环)* @param angle 目标旋转角度(正值为左转,负值为右转)*/
void wheel_rotate(int16_t angle) {PDController pd = {ROTATE_KP, ROTATE_KD, 0};uint16_t initial_z = get_angle_value();uint16_t target_z = (uint16_t)((initial_z + angle + 360) % 360);if (angle < 0) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);} else {tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);}set_all_pwm_channels(0);while (1) {uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(target_z, z);if (abs(diff) < 2) {break;}float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t speed = (uint16_t)fabs(output);if (speed < MIN_ROTATION_DUTY_CYCLE) {speed = MIN_ROTATION_DUTY_CYCLE;} else if (speed > ROTATION_SPEED) {speed = ROTATION_SPEED;}set_all_pwm_channels(speed);}set_all_pwm_channels(0);
}
4.带编码的陀螺仪闭环函数
这种的话是带陀螺仪返款的运动,同时根据设定值运动到指定值停止
(1)前进
/*** @brief 带编码器闭环直行* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_forward_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_forward(z, speed);}set_all_pwm_channels(0);
}
(2)后退
/*** @brief 带编码器闭环后退* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_back_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_back(z, speed);}set_all_pwm_channels(0);
}
(3)左移
/*** @brief 带编码器闭环左移* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_left_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_left(z, speed);}set_all_pwm_channels(0);
}
(4)右移
/*** @brief 带编码器闭环右移* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_right_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_right(z, speed);}set_all_pwm_channels(0);
}
四.测试函数
通过调用测试函数,来判断轮子的方向极性是否正确
/*** @brief 轮子极性测试函数,依次调用开环和闭环控制函数测试轮子运动极性*/
void wheel_polarity_test(void) {const uint16_t distance = 1000;const uint16_t speed = 300;wheel_go_forward_openloop(0);// 开环测试// 1234 编号轮子依次正转set_all_pwm_channels_separate(300, 0, 0, 0);HAL_Delay(500);set_all_pwm_channels_separate(0, 300, 0, 0);HAL_Delay(500);set_all_pwm_channels_separate(0, 0, 300, 0);HAL_Delay(500);set_all_pwm_channels_separate(0, 0, 0, 300);HAL_Delay(500);wheel_stop();HAL_Delay(500);// 左转wheel_rotate_left_openloop(speed);HAL_Delay(500);// 右转wheel_rotate_right_openloop(speed);HAL_Delay(500);// 正左转wheel_go_left_openloop(speed);HAL_Delay(500);// 正右转wheel_go_right_openloop(speed);HAL_Delay(500);// 前进wheel_go_forward_openloop(speed);HAL_Delay(500);// 后退wheel_go_back_openloop(speed);HAL_Delay(500);// 闭环距离测试// 前进wheel_go_forward_count_close(distance, speed);HAL_Delay(500);// 后退wheel_go_back_count_close(distance, speed);HAL_Delay(500);// 左移wheel_go_left_count_close(distance, speed);HAL_Delay(500);// 右移wheel_go_right_count_close(distance, speed);HAL_Delay(500);//左转90度wheel_rotate(90);wheel_stop();HAL_Delay(500);//右转90度wheel_rotate(-90);wheel_stop();HAL_Delay(500);}
五.使用方法
1.首先确定轮子的极性,把下列引脚对应好
/* 硬件相关宏定义
1 4
2 3
*/
// TB6612 方向引脚定义
#define MOTOR1_PIN_A_PORT GPIOA
#define MOTOR1_PIN_A_PIN (1 << 8)
#define MOTOR1_PIN_B_PORT GPIOC
#define MOTOR1_PIN_B_PIN (1 << 9)#define MOTOR2_PIN_A_PORT GPIOC
#define MOTOR2_PIN_A_PIN (1 << 8)
#define MOTOR2_PIN_B_PORT GPIOD
#define MOTOR2_PIN_B_PIN (1 << 13)#define MOTOR3_PIN_A_PORT GPIOD
#define MOTOR3_PIN_A_PIN (1 << 9)
#define MOTOR3_PIN_B_PORT GPIOD
#define MOTOR3_PIN_B_PIN (1 << 10)#define MOTOR4_PIN_A_PORT GPIOD
#define MOTOR4_PIN_A_PIN (1 << 11)
#define MOTOR4_PIN_B_PORT GPIOD
#define MOTOR4_PIN_B_PIN (1 << 12)/* 定时器相关宏定义 */
#define PWM_TIMER &htim1
#define PWM_CHANNEL_1 TIM_CHANNEL_1
#define PWM_CHANNEL_2 TIM_CHANNEL_2
#define PWM_CHANNEL_3 TIM_CHANNEL_3
#define PWM_CHANNEL_4 TIM_CHANNEL_4/* 编码器相关宏定义 */
#define ENCODER_CHA_1_PIN GPIO_PIN_4
#define ENCODER_CHA_1_PORT GPIOA
#define ENCODER_CHA_2_PIN GPIO_PIN_2
#define ENCODER_CHA_2_PORT GPIOB
#define ENCODER_CHA_3_PIN GPIO_PIN_6
#define ENCODER_CHA_3_PORT GPIOE
#define ENCODER_CHA_4_PIN GPIO_PIN_12
#define ENCODER_CHA_4_PORT GPIOE
然后这个函数的返回值修改成自己陀螺仪的返回值函数
/*** @brief 获取当前角度值* @return 当前角度值,调用 get_xyz_z 函数获取*/
uint16_t get_angle_value()
{return (uint16_t)get_xyz_z();
}
2.极性正确测试
添加头文件wheel.h,在主函数添加初始化函数wheel_init();,然后在while(1)中只运行调用测试程序wheel_polarity_test() ,看看轮子是否按着1234编号运动,不是请修改
3.陀螺仪极性
随后看看左转和右转是不是以最近角度旋转,如果不是那么就是极性反了
基本上没有问题后就可以正常使用了
六.完整代码
wheel.c
#include "wheel.h"
#include "gpio.h"
#include "hand.h"
#include "tim.h"
#include "wtkj.h"
#include <stdio.h>
#include <math.h>/* ==================== 辅助函数 ==================== *//*** @brief 确保计算后的速度不小于0* @param speed 当前速度值* @param error 误差值* @return 调整后的速度值*/
uint16_t clamp_speed(uint16_t speed, uint16_t error) {if (speed > error) {return speed - error;}return 0;
}/*** @brief 限制速度在合理范围* @param speed 当前速度值* @param max_speed 最大速度限制* @return 调整后的速度值*/
uint16_t limit_speed(uint16_t speed, uint16_t max_speed) {if (speed > max_speed) {return max_speed;}return speed;
}/* ==================== 基础控制函数 ==================== *//*** @brief 设置四个通道PWM占空比(相同值)* @param speed PWM占空比值*/
void set_all_pwm_channels(uint16_t speed) {__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_1, speed);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_2, speed);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_3, speed);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_4, speed);
}/*** @brief 设置四个通道PWM占空比(不同值)* @param speed1 通道1PWM值* @param speed2 通道2PWM值* @param speed3 通道3PWM值* @param speed4 通道4PWM值*/
void set_all_pwm_channels_separate(uint16_t speed1, uint16_t speed2, uint16_t speed3, uint16_t speed4) {__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_1, speed1);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_2, speed2);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_3, speed3);__HAL_TIM_SetCompare(PWM_TIMER, PWM_CHANNEL_4, speed4);
}/*** @brief 控制TB6612电机方向* @param motor_num 电机编号(1-4)* @param polarity 方向(0或1)*/
void tb6612_set_direction(uint8_t motor_num, uint8_t polarity) {switch (motor_num) {case 1:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR1_PIN_A_PORT, MOTOR1_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR1_PIN_B_PORT, MOTOR1_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR1_PIN_A_PORT, MOTOR1_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR1_PIN_B_PORT, MOTOR1_PIN_B_PIN, 1);}break;case 2:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR2_PIN_A_PORT, MOTOR2_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR2_PIN_B_PORT, MOTOR2_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR2_PIN_A_PORT, MOTOR2_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR2_PIN_B_PORT, MOTOR2_PIN_B_PIN, 1);}break;case 3:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR3_PIN_A_PORT, MOTOR3_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR3_PIN_B_PORT, MOTOR3_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR3_PIN_A_PORT, MOTOR3_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR3_PIN_B_PORT, MOTOR3_PIN_B_PIN, 1);}break;case 4:if (polarity == 0) {HAL_GPIO_WritePin(MOTOR4_PIN_A_PORT, MOTOR4_PIN_A_PIN, 1);HAL_GPIO_WritePin(MOTOR4_PIN_B_PORT, MOTOR4_PIN_B_PIN, 0);} else {HAL_GPIO_WritePin(MOTOR4_PIN_A_PORT, MOTOR4_PIN_A_PIN, 0);HAL_GPIO_WritePin(MOTOR4_PIN_B_PORT, MOTOR4_PIN_B_PIN, 1);}break;default:break;}
}/*** @brief 初始化轮子控制模块*/void wheel_init() {HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); set_all_pwm_channels(0);}/*** @brief 停止所有轮子*/void wheel_stop() {set_all_pwm_channels(0);}/*** @brief 开始运动,重置编码器计数*/
void wheel_begin_go()
{count_save(8);
}/*** @brief 获取编码器平均计数* @return 四个编码器的平均计数值*/
uint16_t wheel_get_count()
{return (count_save(4)+count_save(5)+count_save(6)+count_save(7))/4;
}/*** @brief 编码器计数保存与读取函数* @param cmd 命令码,0-3 为计数加 1,4-7 为读取计数,8 为重置计数* @return 根据命令码返回相应计数值,无返回值命令返回 0*/
int32_t count_save(uint8_t cmd)
{static int32_t count[4]={0};if(cmd<4){count[cmd]++;}else if(cmd<8){return count[cmd-4];}else if(cmd==8){for(uint8_t i=0;i<4;i++)count[i]=0;}return 0;
}/*** @brief GPIO 外部中断回调函数* @param GPIO_Pin 触发中断的 GPIO 引脚*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {switch (GPIO_Pin) {case ENCODER_CHA_1_PIN:count_save(0);break;case ENCODER_CHA_2_PIN:count_save(1);break;case ENCODER_CHA_3_PIN:count_save(2);break;case ENCODER_CHA_4_PIN:count_save(3);break;default:break;}__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}/*** @brief 获取当前角度值* @return 当前角度值,调用 get_xyz_z 函数获取*/
uint16_t get_angle_value()
{return (uint16_t)get_xyz_z();
}/* ==================== 闭环控制函数 ==================== *//*** @brief 计算角度差值* @param target 目标角度* @param current 当前角度* @return 角度差值*/
int16_t calculate_angle_diff(uint16_t target, uint16_t current) {int16_t diff = (int16_t)(target - current);diff = (diff + 180) % 360;if (diff < 0) {diff += 360;}diff -= 180;
#if GYRO_POLARITY == 0diff = -diff;
#endifreturn diff;
}/*** @brief 后退控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/void wheel_go_back(uint16_t now_z, uint16_t speed) {PDController pd = {BACK_KP, BACK_KD, 0};tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}}/*** @brief 直行控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_forward(uint16_t now_z, uint16_t speed) {PDController pd = {STRAIGHT_KP, STRAIGHT_KD, 0};tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}/*** @brief 左移控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_left(uint16_t now_z, uint16_t speed) {PDController pd = {LEFT_KP, LEFT_KD, 0};tb6612_set_direction(1, 1);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 1);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}/*** @brief 右移控制(带陀螺仪闭环)* @param now_z 当前角度* @param speed 目标速度*/
void wheel_go_right(uint16_t now_z, uint16_t speed) {PDController pd = {RIGHT_KP, RIGHT_KD, 0};tb6612_set_direction(1, 0);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 0);uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(now_z, z);float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t adjustment = (uint16_t)fabs(output);adjustment = (adjustment > speed) ? speed : adjustment;if (diff == 0) {set_all_pwm_channels(speed);} else if (diff > 0) {uint16_t left_speed = speed - adjustment;uint16_t right_speed = speed;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);} else {uint16_t left_speed = speed;uint16_t right_speed = speed - adjustment;set_all_pwm_channels_separate(left_speed, left_speed, right_speed, right_speed);}
}/*** @brief 旋转控制(带陀螺仪闭环)* @param angle 目标旋转角度(正值为左转,负值为右转)*/
void wheel_rotate(int16_t angle) {PDController pd = {ROTATE_KP, ROTATE_KD, 0};uint16_t initial_z = get_angle_value();uint16_t target_z = (uint16_t)((initial_z + angle + 360) % 360);if (angle < 0) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);} else {tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);}set_all_pwm_channels(0);while (1) {uint16_t z = get_angle_value();int16_t diff = calculate_angle_diff(target_z, z);if (abs(diff) < 2) {break;}float derivative = diff - pd.prev_error;float output = pd.kp * diff + pd.kd * derivative;pd.prev_error = diff;uint16_t speed = (uint16_t)fabs(output);if (speed < MIN_ROTATION_DUTY_CYCLE) {speed = MIN_ROTATION_DUTY_CYCLE;} else if (speed > ROTATION_SPEED) {speed = ROTATION_SPEED;}set_all_pwm_channels(speed);}set_all_pwm_channels(0);
}/* ==================== 开环控制函数 ==================== *//*** @brief 开环前进* @param speed 目标速度*/
void wheel_go_forward_openloop(uint16_t speed) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);set_all_pwm_channels(speed);
}/*** @brief 开环后退* @param speed 目标速度*/
void wheel_go_back_openloop(uint16_t speed) {tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);set_all_pwm_channels(speed);
}/*** @brief 开环左移* @param speed 目标速度*/
void wheel_go_left_openloop(uint16_t speed) {tb6612_set_direction(1, 1);tb6612_set_direction(2, 0);tb6612_set_direction(3, 0);tb6612_set_direction(4, 1);set_all_pwm_channels(speed);
}/*** @brief 开环右移* @param speed 目标速度*/
void wheel_go_right_openloop(uint16_t speed) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 1);tb6612_set_direction(3, 1);tb6612_set_direction(4, 0);set_all_pwm_channels(speed);
}/*** @brief 开环左转* @param speed 目标速度*/
void wheel_rotate_left_openloop(uint16_t speed) {tb6612_set_direction(1, 1);tb6612_set_direction(2, 1);tb6612_set_direction(3, 0);tb6612_set_direction(4, 0);set_all_pwm_channels(speed);
}/*** @brief 开环右转* @param speed 目标速度*/
void wheel_rotate_right_openloop(uint16_t speed) {tb6612_set_direction(1, 0);tb6612_set_direction(2, 0);tb6612_set_direction(3, 1);tb6612_set_direction(4, 1);set_all_pwm_channels(speed);
}/* ==================== 带编码器的闭环控制函数 ==================== *//*** @brief 带编码器闭环直行* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_forward_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_forward(z, speed);}set_all_pwm_channels(0);
}/*** @brief 带编码器闭环后退* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_back_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_back(z, speed);}set_all_pwm_channels(0);
}/*** @brief 带编码器闭环左移* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_left_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_left(z, speed);}set_all_pwm_channels(0);
}/*** @brief 带编码器闭环右移* @param count 目标编码器计数* @param speed 目标速度*/void wheel_go_right_count_close(uint16_t count, uint16_t speed) {wheel_begin_go();uint16_t z = get_angle_value();while (wheel_get_count() < count) {wheel_go_right(z, speed);}set_all_pwm_channels(0);}/*** @brief 带编码器开环前进* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_forward_count_open(uint16_t count, uint16_t speed)
{// 重置编码器计数wheel_begin_go();// 等待直到编码器计数达到目标值while (wheel_get_count() < count) {wheel_go_forward_openloop(speed);}// 停止电机set_all_pwm_channels(0);
}/*** @brief 带编码器开环后退* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_back_count_open(uint16_t count, uint16_t speed) {wheel_begin_go();while (wheel_get_count() < count) {wheel_go_back_openloop(speed);}set_all_pwm_channels(0);
}/*** @brief 带编码器开环左移* @param count 目标编码器计数* @param speed 目标速度*/
void wheel_go_left_count_open(uint16_t count, uint16_t speed) {wheel_begin_go();while (wheel_get_count() < count) {wheel_go_left_openloop(speed);}set_all_pwm_channels(0);
}/*** @brief 带编码器开环右移* @param count 目标编码器计数* @param speed 目标速度*/void wheel_go_right_count_open(uint16_t count, uint16_t speed) {wheel_begin_go();while (wheel_get_count() < count) {wheel_go_right_openloop(speed);}set_all_pwm_channels(0);}/* ==================== 轮子极性测试函数 ==================== *//*** @brief 轮子极性测试函数,依次调用开环和闭环控制函数测试轮子运动极性*/
void wheel_polarity_test(void) {const uint16_t distance = 1000;const uint16_t speed = 300;wheel_go_forward_openloop(0);// 开环测试// 1234 编号轮子依次正转set_all_pwm_channels_separate(300, 0, 0, 0);HAL_Delay(500);set_all_pwm_channels_separate(0, 300, 0, 0);HAL_Delay(500);set_all_pwm_channels_separate(0, 0, 300, 0);HAL_Delay(500);set_all_pwm_channels_separate(0, 0, 0, 300);HAL_Delay(500);wheel_stop();HAL_Delay(500);// 左转wheel_rotate_left_openloop(speed);HAL_Delay(500);// 右转wheel_rotate_right_openloop(speed);HAL_Delay(500);// 正左转wheel_go_left_openloop(speed);HAL_Delay(500);// 正右转wheel_go_right_openloop(speed);HAL_Delay(500);// 前进wheel_go_forward_openloop(speed);HAL_Delay(500);// 后退wheel_go_back_openloop(speed);HAL_Delay(500);// 闭环距离测试// 前进wheel_go_forward_count_close(distance, speed);HAL_Delay(500);// 后退wheel_go_back_count_close(distance, speed);HAL_Delay(500);// 左移wheel_go_left_count_close(distance, speed);HAL_Delay(500);// 右移wheel_go_right_count_close(distance, speed);HAL_Delay(500);wheel_rotate(90);wheel_stop();HAL_Delay(500);wheel_rotate(-90);wheel_stop();HAL_Delay(500);}
wheel.h
#ifndef WHEEL_H
#define WHEEL_H/*** @file wheel.h* @brief 轮子控制模块头文件*//* 系统头文件包含 */
#include "main.h"/* 硬件相关宏定义 */
// TB6612 方向引脚定义
#define MOTOR1_PIN_A_PORT GPIOA
#define MOTOR1_PIN_A_PIN (1 << 8)
#define MOTOR1_PIN_B_PORT GPIOC
#define MOTOR1_PIN_B_PIN (1 << 9)#define MOTOR2_PIN_A_PORT GPIOC
#define MOTOR2_PIN_A_PIN (1 << 8)
#define MOTOR2_PIN_B_PORT GPIOD
#define MOTOR2_PIN_B_PIN (1 << 13)#define MOTOR3_PIN_A_PORT GPIOD
#define MOTOR3_PIN_A_PIN (1 << 9)
#define MOTOR3_PIN_B_PORT GPIOD
#define MOTOR3_PIN_B_PIN (1 << 10)#define MOTOR4_PIN_A_PORT GPIOD
#define MOTOR4_PIN_A_PIN (1 << 11)
#define MOTOR4_PIN_B_PORT GPIOD
#define MOTOR4_PIN_B_PIN (1 << 12)/* 定时器相关宏定义 */
#define PWM_TIMER &htim1
#define PWM_CHANNEL_1 TIM_CHANNEL_1
#define PWM_CHANNEL_2 TIM_CHANNEL_2
#define PWM_CHANNEL_3 TIM_CHANNEL_3
#define PWM_CHANNEL_4 TIM_CHANNEL_4/* 编码器相关宏定义 */
#define ENCODER_CHA_1_PIN GPIO_PIN_4
#define ENCODER_CHA_1_PORT GPIOA
#define ENCODER_CHA_2_PIN GPIO_PIN_2
#define ENCODER_CHA_2_PORT GPIOB
#define ENCODER_CHA_3_PIN GPIO_PIN_6
#define ENCODER_CHA_3_PORT GPIOE
#define ENCODER_CHA_4_PIN GPIO_PIN_12
#define ENCODER_CHA_4_PORT GPIOE/* 控制参数相关宏定义 */
// 速度控制参数
#define MIN_ROTATION_DUTY_CYCLE 100
#define ROTATION_SPEED 300// PD控制器参数
#define BACK_KP 10 // 后退PD参数
#define BACK_KD 0
#define STRAIGHT_KP 10 // 直行PD参数
#define STRAIGHT_KD 0
#define LEFT_KP 30 // 横向左转PD参数
#define LEFT_KD 0
#define RIGHT_KP 30 // 横向右转PD参数
#define RIGHT_KD 0
#define ROTATE_KP 5 // 旋转PD参数
#define ROTATE_KD 0.2// 陀螺仪配置
#define GYRO_POLARITY 0 // 陀螺仪角度极性,0表示角度减,1表示角度加/* 类型定义 */
typedef struct {float kp; // 比例系数float kd; // 微分系数float prev_error; // 上一次误差
} PDController;/* 函数声明 */
// 初始化函数
void wheel_init(void);
void wheel_begin_go(void);// 基础控制函数
void wheel_stop(void);
void set_all_pwm_channels(uint16_t speed);
void set_all_pwm_channels_separate(uint16_t speed1, uint16_t speed2, uint16_t speed3, uint16_t speed4);
void tb6612_set_direction(uint8_t motor_num, uint8_t polarity);// 闭环控制函数
void wheel_go_back(uint16_t now_z, uint16_t speed);
// 修改函数名
void wheel_go_forward(uint16_t now_z, uint16_t speed);
void wheel_go_right(uint16_t now_z, uint16_t speed);
void wheel_go_left(uint16_t now_z, uint16_t speed);
void wheel_rotate(int16_t angle);// 开环控制函数
void wheel_go_forward_openloop(uint16_t speed);
void wheel_go_back_openloop(uint16_t speed);
void wheel_go_left_openloop(uint16_t speed);
void wheel_go_right_openloop(uint16_t speed);
void wheel_rotate_left_openloop(uint16_t speed);
void wheel_rotate_right_openloop(uint16_t speed);// 带编码器的闭环控制函数
// 修改函数名
void wheel_go_forward_count_close(uint16_t count, uint16_t speed);
void wheel_go_back_count_close(uint16_t count, uint16_t speed);
void wheel_go_left_count_close(uint16_t count, uint16_t speed);
void wheel_go_right_count_close(uint16_t count, uint16_t speed);// 带编码器的开环控制函数
void wheel_go_forward_count_open(uint16_t count, uint16_t speed);
void wheel_go_back_count_open(uint16_t count, uint16_t speed);
void wheel_go_left_count_open(uint16_t count, uint16_t speed);
void wheel_go_right_count_open(uint16_t count, uint16_t speed);// 辅助函数
uint16_t clamp_speed(uint16_t speed, uint16_t error);
uint16_t get_angle_value(void);
uint16_t wheel_get_count(void);
int32_t count_save(uint8_t cmd);
void wheel_polarity_test(void);#endif // WHEEL_H/*
1 42 3设置好对应编号后使用
wheel_polarity_test(void);
这个函数确定极性是否正确,是否按照
1234编号轮子依次正转
然后
左转
右转
正右转
正左转
后退
前进
的方式运动,如果错误请重新矫正
*/