完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
电机控制
主控板电机驱动芯片为TI的DIV8833芯片,一颗DIV8833芯片可以驱动两个电机,我们有4个电机用到了2个芯片。芯片采用对偶PWM方波输入驱动,频率手册没写,我们先使用10KHZ。 STM32F103RTC6高级定时器1、8都带有对偶PWM输出,我们的主控板用的高级定时器1,悲剧的是定时器1只能输出3路对偶PWM方波和1路普通PWM方波,可是我们有4个轮子,所以最后一个轮子的对偶极只能GPIO来代替控制了。 驱动逻辑表: 驱动资料有了逻辑也清晰了,我们接下要做的就只是按照要求输出几个PWM方波了 第一步:CubMX配置定时器1为PWM对偶模式 第二步:封装初始化、通道控制等电机控制接口(具体封装参照源码motor.c文件),最后给上层提供一个初始化接口,一个通道速度控制接口。(向????滑动查看全部) 1/** 2*@ingroup motor 3* 4*初始化定时器 5*@param none 6*@retrun none 7*/ 8static void moto_pwm_init(void) 9{ 10 11/* USER CODE BEGIN TIM1_Init 0 */ 12 13/* USER CODE END TIM1_Init 0 */ 14 15TIM_ClockConfigTypeDef sClockSourceConfig = {0}; 16TIM_MasterConfigTypeDef sMasterConfig = {0}; 17TIM_OC_InitTypeDef sConfigOC = {0}; 18TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; 19 20/* USER CODE BEGIN TIM1_Init 1 */ 21 22/* USER CODE END TIM1_Init 1 */ 23htim1.Instance = TIM1; 24htim1.Init.Prescaler = 71; 25htim1.Init.CounterMode = TIM_COUNTERMODE_UP; 26htim1.Init.Period = MOTOR_PWM_MAX - 1; 27htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 28htim1.Init.RepetitionCounter = 0; 29htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; 30if (HAL_TIM_Base_Init(&htim1) != HAL_OK) 31{ 32 Error_Handler(); 33} 34sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 35if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) 36{ 37 Error_Handler(); 38} 39if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) 40{ 41 Error_Handler(); 42} 43sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 44sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 45if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) 46{ 47 Error_Handler(); 48} 49sConfigOC.OCMode = TIM_OCMODE_PWM1; 50sConfigOC.Pulse = 0; 51sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; 52sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; 53sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; 54sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; 55sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; 56if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) 57{ 58 Error_Handler(); 59} 60if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) 61{ 62 Error_Handler(); 63} 64if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) 65{ 66 Error_Handler(); 67} 68if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) 69{ 70 Error_Handler(); 71} 72sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; 73sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; 74sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; 75sBreakDeadTimeConfig.DeadTime = 0; 76sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; 77sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW; 78sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; 79if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK) 80{ 81 Error_Handler(); 82} 83/* USER CODE BEGIN TIM1_Init 2 */ 84 85/* USER CODE END TIM1_Init 2 */ 86HAL_TIM_MspPostInit(&htim1); 87 88HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); 89HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); 90HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); 91HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); 92 93LOG_I(“motor pwm initialization ok.rn”); 94 95} 1/** 2*@ingroup motor 3* 4*控制电动机标量控制,正直表示正转,负值表示反转 5* 6*@param ch 控制通道MOTOR_CH1/TMOTOR_CH2/TMOTOR_CH3/MOTOR_CH4,可组合使用MOTOR_CH_1|MOTOR_CH_2 7*@param speed pwm控制量[-1000, 1000] 8*@retrun none 9*/ 10void motor_pwm_set(motor_chx ch, int16_t speed) 11{ 12 13/* 反转 */ 14if (0 》 speed) 15{ 16 if (-MOTOR_PWM_MAX 》 speed) 17 speed = -MOTOR_PWM_MAX; 18 motor_pwm_control(ch, MOTOR_DIR_REVERSE, -speed); 19} 20/* 正转 */ 21else if (0 《 speed) 22{ 23 if (MOTOR_PWM_MAX 《 speed) 24 speed = MOTOR_PWM_MAX; 25 motor_pwm_control(ch, MOTOR_DIR_FORWARD, speed); 26} 27/* 停止 */ 28else 29{ 30 motor_pwm_control(ch, MOTOR_DIR_STOP, speed); 31} 32} 第三步:把主要函数加入Finsh控制台命令中,通过命令调试控制效果 1/* FINSH 调试函数 */ 2#ifdef RT_USING_FINSH 3#include 《finsh.h》 4FINSH_FUNCTION_EXPORT_ALIAS(motor_pwm_control, motor_control, channel direction speed); 5FINSH_FUNCTION_EXPORT_ALIAS(motor_pwm_set, motor_set, channel speed); 6 7/* FINSH 调试命令 */ 8#ifdef FINSH_USING_MSH 9 10#endif /* FINSH_USING_MSH */ 11#endif /* RT_USING_FINSH */ 第四步:通过Finsh控制台调试命令测试电机通道和PWM控制量 编码器数据获取 电机测速我们使用520电机自带的AB相霍尔编码器,编码器线数为390,4倍线数后轮子转一圈收到:390*4=1560个脉冲。 stm32自带AB相霍尔解码器,一个通道需要消耗一个定时器。我们主控板电机2、3、4使用的timer 3/4/5硬件解码,电机1没有接定时器,坑爹啊,那只能用外部中断根据时序解码。 编码器时序: 资料有了思路也清晰了,接下来我们要做的只是初始化一下解码器,把实时编码数读出即可 第一步:CubeMx配置解码定时器和中断 第二步:编写初始化函数和编码器数据获取函数,电机1使用中断解码,电机2、3、4使用定时器解码。(具体代码参照github上面源码,这里不再累述) 1/* TIM init */ 2moto_pwm_init(); 3motor_encode2_init(); 4motor_encode3_init(); 5motor_encode4_init(); 6motor_encode_enable(); 7 8LOG_I(“motor initialization completed.rn”); 第三步:加入Finsh调试函数,旋转轮子查看编码值是否准确。(输入 motor_test -ge实时查看编码器值) 1MSH_CMD_EXPORT(motor_test, motor_test -ge/-q); 1![1565968589135] PID 有了编码器作为反馈器,有了PWM作为控制器,那我们就可以加入PID控制器了。加入PID控制器的目的是精确控制轮子的速度,提供轮子的控制达到一致。 PID原理知识自行百度网上资料一大把,个人理解是: 比例Kp: 粗调,大幅度调节控制量让测量值逼近理论值,但是由于单位较大无法精确到达理论值,有响应快,调节尺度大的特点。 微分Kd: 状态预测,Kd控制的是速度的斜率相当于预测下一步速度的趋势,可以加快调节速度。 积分Ki:细调, 通过微小的积分累加,让测量值不断逼近理论值,细调控制量让测量值逼近理论值。 PID框图: PID公式: 理论知识有了,按照公式做个具体实现就好了! 第一步:实现增量PID刷新公式,具体查看源码(pid.c) 1float pid_update(pid_control_t* pid, float measure_value) 2 第二步:将测量值输出到虚拟波形器软件上面便于观测各个值的当前情况,作者使用的是《山外多功能调试助手》,直接将数据输出到控制台串口。数据发送接口实现如下: 1/* 输出数据到虚拟波形软件 */ 2rt_err_t send_waveform_fomate(void *buf, uint32_t size) 3{ 4 const char start[2] = {0x03, 0xfc}; 5 const char end[2] = {0xfc, 0x03}; 6 rt_device_t console = rt_console_get_device(); 7 8 rt_device_write(console, -1, start, 2); //发送起始字符 9 rt_device_write(console, -1, buf, size);//发送通道数据 10 rt_device_write(console, -1, end, 2); //发送结束字符 11 12 return RT_EOK; 13} 第三步:调节合适的速度刷新周期和PID刷新周期,周期不合适电机会剧烈抖动。作者设置周期为: 1p_car-》pid_sample_time = 20; /* PID刷新间隔ms */ 2p_car-》vct_sample_time = 10; /* 速度刷新间隔ms */ 第四步:调试合适的PID参数,由于作者选用电机一致性不好,所以设置参数时每个轮子正传和反转的PID参数都是独立的。具体实现查看代码: 1wheel_select_pid_kx(&p_car-》m_wheel); /* 根据速度设置PID参数 */ 作者样车PID参数: 1#define CHX_PID_KX_TABLE 2{ 3 {MOTOR_CH1, {1.100, 0.400, 0.500}, {1.100, 0.400, 0.500}}, 4 {MOTOR_CH2, {1.100, 0.400, 0.500}, {1.100, 0.400, 0.500}}, 5 {MOTOR_CH3, {1.100, 0.400, 0.500}, {1.100, 0.400, 0.500}}, 6 {MOTOR_CH4, {0.765, 0.330, 0.100}, {0.260, 0.200, 0.010}}, 7} PS2遥控器 PS2 由手柄与接收器两部分组成,手柄主要负责发送按键信息。都接通电源并打开手柄开关时,手柄与接收器自动配对连接,在未配对成功的状态下,接收器绿灯闪烁,手柄上的灯也会闪烁,配对成功后,接收器上绿灯常亮。 PS2遥控有两个模式一个红灯模式、绿灯模式,区别就是红灯模式遥控输出的是模拟值,绿灯输出的只有最大值。我们输出固定速度选用绿灯模式。 PS2传输协议有点像SPI,不同的是PS2每次传输数据帧都是9个字节,里面包含了各个按键的当前值。 PS2更多详细信息查看:ps2解码通讯手册V1.5.pdf PS2时序图: PS2我们只需要读取遥控数据,一个扫描函数搞定,定期刷新一个按键值即可,具体代码参照(ps2.c): 1int ps2_scan(ps2_ctrl_data_t *pt) 遥控功能 最后只剩遥控功能了,我们只需要将PS2遥控的当前值映射到对应控制值,再将对应控制值映射到轮子即可。 车子方向控制图: 遥控映射到控制值: 1/* PS映射car cmd表格,组合键命令在头添加,单键命令放后面 */ 2car_ps2_cmd_t ps2_to_cmd_table[] = { 3 {PS2_BTN_RIGHT| PS2_BTN_UP, CAR_CMD_FORWARD_RIGHT}, 4 {PS2_BTN_LEFT | PS2_BTN_UP, CAR_CMD_FORWARD_LEFT}, 5 {PS2_BTN_RIGHT| PS2_BTN_DOWN, CAR_CMD_BACK_RIGHT}, 6 {PS2_BTN_LEFT | PS2_BTN_DOWN, CAR_CMD_BACK_LEFT}, 7 {PS2_BTN_UP, CAR_CMD_FORWARD}, 8 {PS2_BTN_DOWN, CAR_CMD_BACK}, 9 {PS2_BTN_RIGHT, CAR_CMD_RIGHT}, 10 {PS2_BTN_LEFT, CAR_CMD_LEFT}, 11 {PS2_BTN_CICLE, CAR_CMD_TURN_RIGHT}, 12 {PS2_BTN_SQUARE, CAR_CMD_TURN_LEFT}, 13}; 控制映射到4个轮子的具体速度值: 1/* 命令映射到几何控制参数 */ 2car_cmd_math_t cmd_to_math_table[] = { 3{CAR_CMD_INVALID, { 0, 0, 0, 0}}, 4{CAR_CMD_STOP, { 0, 0, 0, 0}}, 5{CAR_CMD_FORWARD_LEFT, { 0, 120, 120, 0}}, 6{CAR_CMD_FORWARD_RIGHT, { 120, 0, 0, 120}}, 7{CAR_CMD_BACK_LEFT, {-120, 0, 0, -120}}, 8{CAR_CMD_BACK_RIGHT, { 0, -120, -120, 0}}, 9{CAR_CMD_FORWARD, { 120, 120, 120, 120}}, 10{CAR_CMD_BACK, {-120, -120, -120, -120}}, 11{CAR_CMD_RIGHT, { 120, -120, -120, 120}}, 12{CAR_CMD_LEFT, {-120, 120, 120, -120}}, 13{CAR_CMD_TURN_RIGHT, { 120, -120, 120, -120}}, 14{CAR_CMD_TURN_LEFT, {-120, 120, -120, 120}}, 15}; 再开一个线程定期刷新各个轮子的控制即可。 No.4 视频预览 No.5 经验总结 电机控制电路设计上应该与控制板完全隔离,比如光耦隔离器件,避免电流压降造成主控不稳定。 主控板需要有较强的抗大电流和抗干扰性,一块好的主板事半功倍,主动不稳定容易出现未知问题很难定位。 PDI控制环节速度应尽量使用瞬时速度,也就是说在保证精度的情况下刷新时间要尽量的短。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1767 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1069 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1935浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
728浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
567浏览 3评论
592浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
551浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 00:44 , Processed in 1.023265 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号