基于百科荣创主车电机驱动板程序 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

相关文章

Python实现局域网远程控制电脑

《Python实现局域网远程控制电脑》这篇文章主要为大家详细介绍了如何利用Python编写一个工具,可以实现远程控制局域网电脑关机,重启,注销等功能,感兴趣的小伙伴可以参考一下... 目录1.简介2. 运行效果3. 1.0版本相关源码服务端server.py客户端client.py4. 2.0版本相关源码1

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

EMLOG程序单页友链和标签增加美化

单页友联效果图: 标签页面效果图: 源码介绍 EMLOG单页友情链接和TAG标签,友链单页文件代码main{width: 58%;是设置宽度 自己把设置成与您的网站宽度一样,如果自适应就填写100%,TAG文件不用修改 安装方法:把Links.php和tag.php上传到网站根目录即可,访问 域名/Links.php、域名/tag.php 所有模板适用,代码就不粘贴出来,已经打

跨系统环境下LabVIEW程序稳定运行

在LabVIEW开发中,不同电脑的配置和操作系统(如Win11与Win7)可能对程序的稳定运行产生影响。为了确保程序在不同平台上都能正常且稳定运行,需要从兼容性、驱动、以及性能优化等多个方面入手。本文将详细介绍如何在不同系统环境下,使LabVIEW开发的程序保持稳定运行的有效策略。 LabVIEW版本兼容性 LabVIEW各版本对不同操作系统的支持存在差异。因此,在开发程序时,尽量使用

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

这些心智程序你安装了吗?

原文题目:《为什么聪明人也会做蠢事(四)》 心智程序 大脑有两个特征导致人类不够理性,一个是处理信息方面的缺陷,一个是心智程序出了问题。前者可以称为“认知吝啬鬼”,前几篇文章已经讨论了。本期主要讲心智程序这个方面。 心智程序这一概念由哈佛大学认知科学家大卫•帕金斯提出,指个体可以从记忆中提取出的规则、知识、程序和策略,以辅助我们决策判断和解决问题。如果把人脑比喻成计算机,那心智程序就是人脑的

uniapp设置微信小程序的交互反馈

链接:uni.showToast(OBJECT) | uni-app官网 (dcloud.net.cn) 设置操作成功的弹窗: title是我们弹窗提示的文字 showToast是我们在加载的时候进入就会弹出的提示。 2.设置失败的提示窗口和标签 icon:'error'是设置我们失败的logo 设置的文字上限是7个文字,如果需要设置的提示文字过长就需要设置icon并给

控制反转 的种类

之前对控制反转的定义和解释都不是很清晰。最近翻书发现在《Pro Spring 5》(免费电子版在文章最后)有一段非常不错的解释。记录一下,有道翻译贴出来方便查看。如有请直接跳过中文,看后面的原文。 控制反转的类型 控制反转的类型您可能想知道为什么有两种类型的IoC,以及为什么这些类型被进一步划分为不同的实现。这个问题似乎没有明确的答案;当然,不同的类型提供了一定程度的灵活性,但