基于百科荣创主车电机驱动板程序 PID控制

2023-11-11 01:31

本文主要是介绍基于百科荣创主车电机驱动板程序 PID控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

适用百科荣创新款主车以及麦克纳姆轮的电机驱动板,老款带电子罗盘的实测不适用

代码以及逻辑上可能会存在一些问题,错误的地方在评论区指出

 当时用的370麦轮电机,很难控制,后面指导老师让我们考虑加入pid,原本在主控板的程序里面,效果一般,后面才考虑用hal库重构电机驱动板,但是后面发现效果也没有提升多少,到后面的竞赛平台也就用了这个程序

在看原理图的时候其实发现了一些奇奇怪怪的地方,就比如说前轮可以用定时器捕获功能获取码盘,但是后轮定时器又跟定时器pwm有点冲突,用外部中断的话,有两个轮子的中断线又有冲突,然后电机的pwm又对应互补输出,电机驱动用了TIM8三路互补输出和TIM2两个输出,当时的我stm32也才刚入门,整不明白互补怎么去控制的电机,所以把互补的三路切换到了TIM3的CH1、CH2、CH3上。

码盘用的是TIM1,TIM3,TIM4和TIM5的编码器模式,原电机驱动板只采样后面两个轮子的码盘,这个时候TIM3就已经和输出PWM的TIM3冲突了,TIM3对应的是后面两个轮子的其中一个。想过用外部中断测码盘,但是前面两个电机码盘接的IO的外部中断线又冲突了。
最后是后面两个轮子用定时器TIM1和TIM4来测码盘,前面两个轮子用的是两个外部中断测码盘,又发现前后码盘有个四倍的差距,就直接在中断码盘计数那边改成了+=4和-=4……

 带pid的电机驱动板程序其实并没有多麻烦,麻烦在于挖掘CAN的通信

CuneMX的配置

如图:

 记得开启CAN中断接收

 主要就是一个

CAN中断接收

注:因为用HAL库重构了核心板程序,这里加了一些原厂程序不会有的功能,可能会导致原厂核心板程序搭配这套程序出现问题,原厂应该只会用到0x1e0的接收

u16 Stop_Time=0;
uint8_t TXmessage[8] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
uint8_t RXmessage[8];
uint32_t pTxMailbox = 0;
int Set_MP[4];
u8 Set_MP_Flag = 0;void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)//接受邮箱0挂起中断回调函数
{if(hcan->Instance==CAN1){RxHeader.StdId=0x20;HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO0,&RxHeader,RXmessage);//获取数据switch(RxHeader.StdId){case 0x1e0:{motor_set_left_top = RXmessage[0]/4;    //左前轮设定值motor_set_right_top = RXmessage[2]/4;   //右前轮设定值motor_set_left_aft = RXmessage[1]/4;    //左后轮设定值motor_set_right_aft = RXmessage[3]/4;   //右后轮设定值if(motor_set_left_top>31)motor_set_left_top-=64;if(motor_set_right_top>31)motor_set_right_top-=64;if(motor_set_left_aft>31)motor_set_left_aft-=64;if(motor_set_right_aft>31)motor_set_right_aft-=64;memset(RXmessage,0,8);//清空数组}break;case 0x1e1:{  //让电机转动指定个码盘,已废弃Set_MP[0] = ((RXmessage[1]<<8)+RXmessage[0])/4;Set_MP[1] = ((RXmessage[3]<<8)+RXmessage[2])/4;Set_MP[2] = ((RXmessage[5]<<8)+RXmessage[4])/4;Set_MP[3] = ((RXmessage[7]<<8)+RXmessage[6])/4;if(Set_MP[0]>8191) Set_MP[0]-=16384;if(Set_MP[1]>8191) Set_MP[1]-=16384;if(Set_MP[2]>8191) Set_MP[2]-=16384;if(Set_MP[3]>8191) Set_MP[3]-=16384;printf("%d,%d,%d,%d\n\n",Set_MP[0],Set_MP[1],Set_MP[2],Set_MP[3]);Set_MP_Flag = 1;memset(RXmessage,0,8);//清空数组}break;case 0x1e2:{   //停车三秒if(RXmessage[0]==0x03){Stop_Time = RXmessage[1]*72;}memset(RXmessage,0,8);//清空数组}break;}//printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n",RXmessage[0],RXmessage[1],RXmessage[2],RXmessage[3],RXmessage[4],RXmessage[5],RXmessage[6],RXmessage[7]);}}

以及在网上找的一个

CAN的发送函数

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)	
//len:数据长度(最大为8)				     
//msg:数据指针,最大为8个字节.
//stdid:目标id
//返回值:0,成功;
//		 其他,失败;//disp地址:0x1e
u8 CAN1_Send_Msg(u8* msg,u8 len,u32 stdid,u32 d)
{	u8 i=0;uint32_t TxMailbox;u8 message[8];TxHeader.StdId=stdid;//0X12;        //标准标识符TxHeader.ExtId=0;//0x12;        //扩展标识符(29位)TxHeader.IDE=CAN_ID_STD;    //使用标准帧TxHeader.RTR=CAN_RTR_DATA;  //数据帧TxHeader.DLC=len;    for(i=0;i<len;i++){message[i]=msg[i];}if(HAL_CAN_AddTxMessage(&hcan, &TxHeader, message, &TxMailbox) != HAL_OK)//发送{return 1;}while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3) {}return 0;
}

列出一下

CAN ID对应的目标:

0x1e0:电机驱动板的速度

0x1e1:让电机转动指定个码盘        ****

0x1e2:最高权限让电机驱动板停车多少秒          ****

0x3c0:通信显示板Debug打印

0x1F1:通信显示板显示的码盘

0x0E7:主车程序的循迹板数据回传

0x2A0:ZigBee数据

0x280:WiFi数据

printf重定向

原厂程序的printf重定向:

int fputc(int ch,FILE *p)  //printf重定向到通信显示板的debug
{delay_ms(1);u8 tmp[1];sprintf((char*)tmp,"%c",ch);Send_Debug_Info((u8*)tmp,1);USART_SendData(USART1,(u8)ch);	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);return ch;
}

hal库重构后的重定向

int fputc(int ch,FILE *f)
{CAN1_Send_Msg((uint8_t *)&ch,1,0x3c0,0);return ch;
}

下面是一部分的代码

设置pwm

//设置电机pwm,左前,左后,右前,右后
void set_motor(int lt,int la,int rt,int ra)
{if(rt>0){__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,rt);//右前轮正转__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_4,0);//右前轮反转}else if(rt==0){__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,1000);//右前轮正转__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_4,1000);//右前轮反转}else{__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,0);//右前轮正转__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_4,-rt);//右前轮反转}if(ra>0){__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,ra);//右后轮正转__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,0);//右后轮反转}else if(ra==0){__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,1000);//右后轮正转__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,1000);//右后轮反转}else{__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,0);//右后轮正转__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,-ra);//右后轮反转}if(lt>0){__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,lt);//左前轮正转__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,0);//左前轮反转}else if(lt==0){__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,1000);//左前轮正转__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,1000);//左前轮反转}else{__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,0);//左前轮正转__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,-lt);//左前轮反转}if(la>0){__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_3,la);//左后轮正转__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,0);//左后轮反转}else if(la==0){__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_3,1000);//左后轮正转__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,1000);//左后轮反转 }else{__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_3,0);//左后轮正转__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,-la);//左后轮反转      }}

转速 PID

//电机转速pidfloat Kp = 1.2;
float Ki = 0.3;
float Kd = 2;/*
函数功能:PID左前计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int pid_lt(int test,int set)
{static int Bias,Pwm,Old_Last_bias,Last_bias;Bias=set-test;             //计算偏差Pwm=Kp*(Bias-Last_bias)+Ki*Bias+Kd*(Bias-(2*Last_bias)+Old_Last_bias);  //增量式PI控制器Old_Last_bias=Last_bias;	                   //保存上上一次偏差Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}/*
函数功能:PID左后计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int pid_la(int test,int set)
{static int Bias,Pwm,Old_Last_bias,Last_bias;Bias=set-test;             //计算偏差Pwm=Kp*(Bias-Last_bias)+Ki*Bias+Kd*(Bias-(2*Last_bias)+Old_Last_bias);  //增量式PI控制器Old_Last_bias=Last_bias;	                   //保存上上一次偏差Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}/*
函数功能:PID右前计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int pid_rt(int test,int set)
{static int Bias,Pwm,Old_Last_bias,Last_bias;Bias=set-test;             //计算偏差Pwm=Kp*(Bias-Last_bias)+Ki*Bias+Kd*(Bias-(2*Last_bias)+Old_Last_bias);  //增量式PI控制器Old_Last_bias=Last_bias;	                   //保存上上一次偏差Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}/*
函数功能:PID右后计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int pid_ra(int test,int set)
{static int Bias,Pwm,Old_Last_bias,Last_bias;Bias=set-test;             //计算偏差Pwm=Kp*(Bias-Last_bias)+Ki*Bias+Kd*(Bias-(2*Last_bias)+Old_Last_bias);  //增量式PI控制器Old_Last_bias=Last_bias;	                   //保存上上一次偏差Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}

位置PID

//码盘位置pidfloat cmd_P = 3;
float cmd_I = 0.0005;
float cmd_D = 12;/*
函数功能:PID左前计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int wz_pid_lt(int test,int set)
{float Kp=cmd_P,Ki=cmd_I,Kd=cmd_D;			//原例程中Kp=20,Ki=30	static int Bias,Pwm,Integral_bias,Last_bias;Bias=set-test;             //计算偏差Integral_bias+=Bias;Pwm=Kp*Bias+Ki*Integral_bias+Kd*(Bias-Last_bias);  //位置式PI控制器Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}/*
函数功能:PID左后计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int wz_pid_la(int test,int set)
{float Kp=cmd_P,Ki=cmd_I,Kd=cmd_D;			//原例程中Kp=20,Ki=30	static int Bias,Pwm,Integral_bias,Last_bias;Bias=set-test;             //计算偏差Integral_bias+=Bias;Pwm=Kp*Bias+Ki*Integral_bias+Kd*(Bias-Last_bias);  //位置式PI控制器Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}/*
函数功能:PID右前计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int wz_pid_rt(int test,int set)
{float Kp=cmd_P,Ki=cmd_I,Kd=cmd_D;			//原例程中Kp=20,Ki=30	static int Bias,Pwm,Integral_bias,Last_bias;Bias=set-test;             //计算偏差Integral_bias+=Bias;Pwm=Kp*Bias+Ki*Integral_bias+Kd*(Bias-Last_bias);  //位置式PI控制器Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}/*
函数功能:PID右后计算
参    数:test:当前车速,set:设置车速
返 回 值:无
*/
int wz_pid_ra(int test,int set)
{float Kp=cmd_P,Ki=cmd_I,Kd=cmd_D;			//原例程中Kp=20,Ki=30	static int Bias,Pwm,Integral_bias,Last_bias;Bias=set-test;             //计算偏差Integral_bias+=Bias;Pwm=Kp*Bias+Ki*Integral_bias+Kd*(Bias-Last_bias);  //位置式PI控制器Last_bias=Bias;	                   //保存上一次偏差return Pwm;                        //增量输出
}

定时器中断

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //外部中断回调函数
{if(GPIO_Pin == GPIO_PIN_0){if(HAL_GPIO_ReadPin(CODE_D2_GPIO_Port,CODE_D2_Pin)==1){code_desk_left_top+=4;}else{code_desk_left_top-=4;}}if(GPIO_Pin == GPIO_PIN_4){if(HAL_GPIO_ReadPin(CODE_B2_GPIO_Port,CODE_B2_Pin)==1){code_desk_right_top-=4;}else{code_desk_right_top+=4;}}}u16 mp_delay=0;
int code_disk_init[4];void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim==(&htim6))//PID定时器6{static int tmp[4];int speed[4];code_desk_left_aft-=	(short)__HAL_TIM_GET_COUNTER(&htim4);	  //读取左后轮编码器数据code_desk_right_aft+=	(short)__HAL_TIM_GET_COUNTER(&htim1);	  //读取右后轮编码器数据__HAL_TIM_GET_COUNTER(&htim4) = 0;							  //计数器值重新置位__HAL_TIM_GET_COUNTER(&htim1) = 0;							  //计数器值重新置位//做减法计算速度speed[0]=tran_reduce(code_desk_left_top,tmp[0]);speed[1]=tran_reduce(code_desk_right_top,tmp[1]);speed[2]=tran_reduce(code_desk_left_aft,tmp[2]);speed[3]=tran_reduce(code_desk_right_aft,tmp[3]);//保存老的码盘数值tmp[0]=code_desk_left_top;tmp[1]=code_desk_right_top;tmp[2]=code_desk_left_aft;tmp[3]=code_desk_right_aft;if(Set_MP_Flag) //位置pid模式{if(mp_delay==0){code_disk_init[0] = code_desk_left_top;code_disk_init[1] = code_desk_right_top;code_disk_init[2] = code_desk_left_aft;code_disk_init[3] = code_desk_right_aft;}if(++mp_delay>144)//执行时间{mp_delay=0;Set_MP_Flag=0;}if((abs(code_desk_left_top-(code_disk_init[0]+Set_MP[0]))<20)&&(abs(code_desk_right_top-(code_disk_init[1]+Set_MP[1]))<20)&&(abs(code_desk_left_aft-(code_disk_init[2]+Set_MP[2]))<20)&&(abs(code_desk_right_aft-(code_disk_init[3]+Set_MP[3]))<20)){mp_delay=0;Set_MP_Flag=0;}pwm[0]=wz_pid_lt(code_desk_left_top,code_disk_init[0]+Set_MP[0]);pwm[1]=wz_pid_rt(code_desk_right_top,code_disk_init[1]+Set_MP[2]);pwm[2]=wz_pid_la(code_desk_left_aft,code_disk_init[2]+Set_MP[1]);pwm[3]=wz_pid_ra(code_desk_right_aft,code_disk_init[3]+Set_MP[3]);u8 max_speed = 60;//不让pwm超太多if(pwm[0]>max_speed)pwm[0]=max_speed;if(pwm[1]>max_speed)pwm[1]=max_speed;if(pwm[2]>max_speed)pwm[2]=max_speed;if(pwm[3]>max_speed)pwm[3]=max_speed;if(pwm[0]<-max_speed)pwm[0]=-max_speed;if(pwm[1]<-max_speed)pwm[1]=-max_speed;if(pwm[2]<-max_speed)pwm[2]=-max_speed;if(pwm[3]<-max_speed)pwm[3]=-max_speed;//printf("%d,%d\n",code_desk_right_aft,code_disk_init[3]+Set_MP[3]);}else{//PID计算pwm[0]+=pid_lt(speed[0],motor_set_left_top);pwm[1]+=pid_rt(speed[1],motor_set_right_top);pwm[2]+=pid_la(speed[2],motor_set_left_aft);pwm[3]+=pid_ra(speed[3],motor_set_right_aft);//清零if(motor_set_left_top==0)pwm[0]=0;if(motor_set_right_top==0)pwm[1]=0;if(motor_set_left_aft==0)pwm[2]=0;if(motor_set_right_aft==0)pwm[3]=0;//不让pwm超太多if(pwm[0]>100)pwm[0]=100;if(pwm[1]>100)pwm[1]=100;if(pwm[2]>100)pwm[2]=100;if(pwm[3]>100)pwm[3]=100;if(pwm[0]<-100)pwm[0]=-100;if(pwm[1]<-100)pwm[1]=-100;if(pwm[2]<-100)pwm[2]=-100;if(pwm[3]<-100)pwm[3]=-100;}if(Stop_Time>0){Stop_Time--;pwm[0] = 0;pwm[1] = 0;pwm[2] = 0;pwm[3] = 0;}//模式切换if(mode_flag==0) set_motor(pwm[0]*10,pwm[2]*10,pwm[1]*10,pwm[3]*10);if(mode_flag==1) set_motor(motor_set_left_top*10,motor_set_left_aft*10,motor_set_right_top*10,motor_set_right_aft*10);//        printf("set:%3d,%3d,%3d,%3d",motor_set_left_top,motor_set_left_aft,motor_set_right_top,motor_set_right_aft);
//        printf("   pwm:%3d,%3d,%3d,%3d",pwm[0],pwm[1],pwm[2],pwm[3]);
//        printf("   speed %3d,%3d,%3d,%3d",speed[0],speed[1],speed[2],speed[3]);
//        printf("   mp:%3d,%3d,%3d,%3d",code_desk_left_top,code_desk_right_top,code_desk_left_aft,code_desk_right_aft);
//        printf("   vol:%d\n",HAL_ADC_GetValue(&hadc1));// printf("%d,%d,%d,%d\n\n",Set_MP[0],Set_MP[1],Set_MP[2],Set_MP[3]);//        //发送给主车以及通信显示板的码盘    
//        u8 dat[]={0x02,((code_desk_left_top*4)&0xFF),(((code_desk_left_top*4) >>8)&0xFF),((code_desk_right_top*4)&0xFF),(((code_desk_right_top*4) >>8)&0xFF),0x00,(motor_volta)&0xFF,(motor_volta>>8)&0xFF};
//        u8 dat2[]={0x03,((code_desk_left_aft*4)&0xFF),(((code_desk_left_aft*4) >>8)&0xFF),((code_desk_right_aft*4)&0xFF),(((code_desk_right_aft*4) >>8)&0xFF),0x00,0x00,0x00};
//        CAN1_Send_Msg(dat,8,0x01E0,0);
//        CAN1_Send_Msg(dat2,8,0x01E1,0);
//        
//        u8 dat2[]={pwm[0],pwm[2],pwm[1],pwm[3],0x00,0x00,0x00,0x00};
//        CAN1_Send_Msg(dat2,8,0x01,0);}
}

主循环

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_ADC1_Init();MX_CAN_Init();MX_TIM2_Init();MX_TIM8_Init();MX_USART2_UART_Init();MX_TIM3_Init();MX_TIM4_Init();MX_TIM1_Init();MX_TIM6_Init();/* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim6);HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_4);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);//电机驱动芯片的睡眠关闭HAL_GPIO_WritePin(SLEEP_AB_GPIO_Port,SLEEP_AB_Pin,GPIO_PIN_SET);HAL_GPIO_WritePin(SLEEP_CD_GPIO_Port,SLEEP_CD_Pin,GPIO_PIN_SET);HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_1 | TIM_CHANNEL_2);HAL_TIM_Encoder_Start(&htim1,TIM_CHANNEL_1 | TIM_CHANNEL_2);HAL_Delay(2000);CAN1_Send_Msg("PID mode",8,0x3c0,0);   //上电默认pid模式CAN1_Send_Msg("\n",1,0x3c0,0);   //上电默认pid模式//printf("PID Mode\n");HAL_ADCEx_Calibration_Start(&hadc1);    //AD校准HAL_ADC_Start(&hadc1);// 读取RCC_CSR寄存器的值uint32_t resetFlags = RCC->CSR;printf("motor:");// 判断重启原因if ((resetFlags & RCC_CSR_SFTRSTF) != 0) {// 软件复位printf("Software Reset\n");} else if ((resetFlags & RCC_CSR_PORRSTF) != 0) {// 上电复位printf("Power-On Reset\n");} else if ((resetFlags & RCC_CSR_PINRSTF) != 0) {// 外部引脚复位printf("Pin Reset\n");} else if ((resetFlags & RCC_CSR_IWDGRSTF) != 0) {// 独立看门狗复位printf("Independent Watchdog Reset\n");} else if ((resetFlags & RCC_CSR_WWDGRSTF) != 0) {// 窗口看门狗复位printf("Window Watchdog Reset\n");} else if ((resetFlags & RCC_CSR_LPWRRSTF) != 0) {// 低功耗复位printf("Low-Power Reset\n");} else if ((resetFlags & RCC_CSR_RMVF) != 0) {// 电源复位printf("Brown-Out Reset\n");}// 清除复位标志RCC->CSR |= RCC_CSR_RMVF;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(key_scan()==1){mode_flag++;switch(mode_flag){case 0:CAN1_Send_Msg("PID mode\n",8,0x3c0,0);break;//发送到debugcase 1:CAN1_Send_Msg("Common\n",8,0x3c0,0);break;case 2:CAN1_Send_Msg("Debug\n",6,0x3c0,0);set_motor(300,0,0,0);break;case 3:set_motor(0,300,0,0);break;case 4:set_motor(0,0,300,0);break;case 5:set_motor(0,0,0,300);break;case 6:set_motor(300,300,300,300);break;case 7:set_motor(0,0,0,0);break;             case 8:set_motor(-300,0,0,0);break;case 9:set_motor(0,-300,0,0);break;case 10:set_motor(0,0,-300,0);break;case 11:set_motor(0,0,0,-300);break;case 12:set_motor(-300,-300,-300,-300);break;case 13:set_motor(0,0,0,0);mode_flag=-1;break;}}HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);//发送给主车以及通信显示板的码盘    u8 dat[]={0x02,((code_desk_left_top)&0xFF),(((code_desk_left_top) >>8)&0xFF),((code_desk_right_top)&0xFF),(((code_desk_right_top) >>8)&0xFF),0x00,(motor_volta)&0xFF,(motor_volta>>8)&0xFF};u8 dat2[]={0x03,((code_desk_left_aft)&0xFF),(((code_desk_left_aft) >>8)&0xFF),((code_desk_right_aft)&0xFF),(((code_desk_right_aft) >>8)&0xFF),0x00,0x00,0x00};CAN1_Send_Msg(dat,8,0x01E0,0);HAL_Delay(15);CAN1_Send_Msg(dat2,8,0x01F1,0);motor_volta = HAL_ADC_GetValue(&hadc1);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

国赛完成,后面有机会开源hal库的主车程序,以及抛弃arduino后的从车stm32程序和视频循迹

这篇关于基于百科荣创主车电机驱动板程序 PID控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/386652

相关文章

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

使用DrissionPage控制360浏览器的完美解决方案

《使用DrissionPage控制360浏览器的完美解决方案》在网页自动化领域,经常遇到需要保持登录状态、保留Cookie等场景,今天要分享的方案可以完美解决这个问题:使用DrissionPage直接... 目录完整代码引言为什么要使用已有用户数据?核心代码实现1. 导入必要模块2. 关键配置(重点!)3.

SpringSecurity 认证、注销、权限控制功能(注销、记住密码、自定义登入页)

《SpringSecurity认证、注销、权限控制功能(注销、记住密码、自定义登入页)》SpringSecurity是一个强大的Java框架,用于保护应用程序的安全性,它提供了一套全面的安全解决方案... 目录简介认识Spring Security“认证”(Authentication)“授权” (Auth

python之流程控制语句match-case详解

《python之流程控制语句match-case详解》:本文主要介绍python之流程控制语句match-case使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录match-case 语法详解与实战一、基础值匹配(类似 switch-case)二、数据结构解构匹

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

Spring Security注解方式权限控制过程

《SpringSecurity注解方式权限控制过程》:本文主要介绍SpringSecurity注解方式权限控制过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、摘要二、实现步骤2.1 在配置类中添加权限注解的支持2.2 创建Controller类2.3 Us

基于Python开发PDF转Doc格式小程序

《基于Python开发PDF转Doc格式小程序》这篇文章主要为大家详细介绍了如何基于Python开发PDF转Doc格式小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用python实现PDF转Doc格式小程序以下是一个使用Python实现PDF转DOC格式的GUI程序,采用T

Python中如何控制小数点精度与对齐方式

《Python中如何控制小数点精度与对齐方式》在Python编程中,数据输出格式化是一个常见的需求,尤其是在涉及到小数点精度和对齐方式时,下面小编就来为大家介绍一下如何在Python中实现这些功能吧... 目录一、控制小数点精度1. 使用 round() 函数2. 使用字符串格式化二、控制对齐方式1. 使用