(1) Electromagnetic treatment
In this smart car competition, I chose camera based and electromagnetic simple auxiliary path planning to help the body quickly return to the right after turning out, but later, due to the electromagnetic line of the field, I turned off electromagnetic assistance and adopted pure camera tracking.
For electromagnetic tracking, I don't use normalization, just simple difference ratio and processing
Diangan dg; void Read_ADC() { int16 i,j,temp; static int16 value_temp[5][5]={0}; //Line: five inductors Column: each inductance has its own five sets of mean values int16 value_sum[5]={0}; int16 value_ave[5]={0}; for(j=0;j<5;j++) { value_temp[0][j] = adc_mean_filter(ADC_1,ADC1_CH10_B21,5); //Take 5 samples and take the average value value_temp[1][j] = adc_mean_filter(ADC_1,ADC1_CH7_B18,5); value_temp[2][j] = adc_mean_filter(ADC_1,ADC1_CH8_B19,5); value_temp[3][j] = adc_mean_filter(ADC_1,ADC1_CH5_B16,5); value_temp[4][j] = adc_mean_filter(ADC_1,ADC1_CH6_B17,5); } /*=======================Bubble sorting=================================*/ for(i=0;i<5;i++) { for (j=0;j<4;j++) { if(value_temp[i][j]>value_temp[i][j+1]) { temp = value_temp[i][j]; value_temp[i][j] = value_temp[i][j+1]; value_temp[i][j+1] = temp; } } } /*============Median filter==========================================*/ //Find the sum of the middle three terms The maximum and minimum of the five groups of values collected by each inductance are rounded off and the rest is averaged for(i=0;i<5;i++) { value_sum[i] = value_temp[i][1] + value_temp[i][2] + value_temp[i][3]; value_ave[i] = (int)(value_sum[i]/3); } dg.Middle_vlaue = value_ave[4]; for(i=0;i<9;i++) { value_ave[i] = value_ave[i]/10*10; } dg.Left_heng = value_ave[0]; //B21 dg.Left_shu = value_ave[1]; //B18 dg.Right_heng = value_ave[3]; //B16 dg.Right_shu = value_ave[2]; //B19 dg.Middle_heng = value_ave[4]-1000; //B17 } void ADC_deal() { static float LevelTemp[5]; // Comparison and preservation of the last 5 times static float shuzhiTemp[5]; // static float ad_M_max=3400; // static float ad_M_min =2800; dg.shuiping_error = (int)((float)( dg.Left_heng - dg.Right_heng )/( dg.Left_heng + dg.Right_heng )* 100);//Horizontal inductance difference ratio and dg.shuzhi_error = (int)((float)( dg.Left_shu - dg.Right_shu )/( dg.Left_shu + dg.Right_shu )* 100);//Inner eight inductance difference ratio sum LevelTemp[4] = LevelTemp[3]; LevelTemp[3] = LevelTemp[2]; LevelTemp[2] = LevelTemp[1]; LevelTemp[1] = LevelTemp[0]; LevelTemp[0] = dg.shuiping_error; dg.shuiping_error_d =(int)(LevelTemp[0]-LevelTemp[3]);//Horizontal inductance deviation differential shuzhiTemp[4] = shuzhiTemp[3]; shuzhiTemp[3] = shuzhiTemp[2]; shuzhiTemp[2] = shuzhiTemp[1]; shuzhiTemp[1] = shuzhiTemp[0]; shuzhiTemp[0] = dg.shuzhi_error; dg.shuzhi_error_d = (int)(shuzhiTemp[0]-shuzhiTemp[3]);//Vertical inductance deviation differential // // if(dg.Middle_vlaue<ad_M_min) ad_M_min = dg.Middle_vlaue; // if(dg.Middle_vlaue>ad_M_max) ad_M_max = dg.Middle_vlaue; // dg.Middle_heng=(float)(dg.Middle_vlaue-ad_M_min)/(ad_M_max-ad_M_min); // dg.mid_normalized =(int)(100*dg.Middle_heng); }
About my error value, 0.7 * (camera error) + 0.4 (inductance error):
car.Error=(int)((SteerSum)*0.7+dg.shuiping_error *0.4);
(2) Gyroscope use
For the use of gyroscope, before the competition, I thought that the gyroscope could only be used on the ramp in addition to the double car group. In fact, it is not. In the competition, the gyroscope can assist the values transmitted through the three axes to calculate the deviation angle. After turning, the Z-axis value can assist the body to quickly return to the right. When entering and leaving the ring and entering and leaving the garage, The conditions can also be judged by integrating the gyroscope.
//Simple mpu6050 conversion gyro_x = ((float)mpu_gyro_x)*0.5f)/(16.384f); gyro_y = ((float)mpu_gyro_y)*0.5f)/(16.384f); gyro_z = ((float)mpu_gyro_z)*0.5f)/(16.384f);
(3) Encoder closed loop
I once saw a great God say that if the closed-loop motor is adjusted for two days, it will run faster than the open-loop motor. It can be seen that the importance of closed-loop control. For the closed-loop control of the motor, it is mainly through the difference between the set speed and the return speed of the encoder, and then carry out pid calculation. There are many excellent articles on pid on the Internet, whether it is open source or explanation. I can't explain it more. Here I post the incremental pid code of my race. For different track elements, we can set different speeds.
void Get_speed() { //Read encoder count Speed.left_encoder = -qtimer_quad_get(QTIMER_1,QTIMER1_TIMER2_C2); Speed.right_encoder = qtimer_quad_get(QTIMER_1,QTIMER1_TIMER0_C0); qtimer_quad_clear(QTIMER_1,QTIMER1_TIMER0_C0); qtimer_quad_clear(QTIMER_1,QTIMER1_TIMER2_C2); Speed.encoder_l=(int32)(Speed.left_encoder+0.00001); Speed.encoder_r=(int32)(Speed.right_encoder+0.00001); Speed.encoder = (int32)((Speed.left_encoder + Speed.right_encoder + 0.00001)/2); } int16 error0,error1,error2; void motor_pid() { Get_speed(); float P,I,D; //Left motor error0 = error1 = error2 = 0; error0 = targrt_speed - Speed.encoder_l;//I error1 = error0 - pidl.lastError;//P error2 = error0 - 2*pidl.lastError + pidl.preError;//D pidl.preError = pidl.lastError; pidl.lastError = error0; P=speed_P; I=speed_I; D=speed_D; pidl.PWM += (int16)(P*error1 + I*error0 + D*error2); if(pidl.PWM > 30000) pidl.PWM = 30000; if(pidl.PWM < -9999) pidl.PWM = -9999; //Right motor error0 = error1 = error2 = 0; error0 = targrt_speed - Speed.encoder_r;//I error1 = error0 - pidr.lastError;//P error2 = error0 - 2*pidr.lastError + pidr.preError;//D pidr.preError = pidr.lastError; pidr.lastError = error0; P=speed_P; I=speed_I; D=speed_D; pidr.PWM +=(int16)(P*error1 + I*error0 + D*error2); if(pidr.PWM > 30000) pidr.PWM = 30000; if(pidr.PWM < -9999) pidr.PWM = -9999; pidl.PWM += (int16)(P*error1 + I*error0 + D*error2); pidr.PWM +=(int16)(P*error1 + I*error0 + D*error2); Motor_pwm_out(pidl.PWM,pidr.PWM ); }
For how to adjust the motor pid, we can send the waveform through the serial port through the host computer outside the mountain and change the size of the three values until the waveform is perfect
//Send serial port to upper computer void display_sendware() { int8 a[6]={0}; a[0]=targrt_speed; a[1]=targrt_speed>>8; a[2]=(int16)Speed.left_encoder; a[3]=(int16)Speed.left_encoder>>8; a[4]=(int16)pidl.PWM; a[5]=(int16)pidl.PWM>>8; vcan_sendware((uint8*)a,6); }
Just adjust the approximate waveform to this shape
Because there is no debugging waveform on hand, it can only be roughly drawn. Red is the speed you set and blue is the value returned by the encoder. When the motor is turned on, the encoder value can respond quickly and vibrate quickly in a small range around the set speed.
(4) Zebra crossing detection
The image collected by the camera can be judged by code, but if it is pure electromagnetic judgment, it can be judged by reed and infrared tube. However, due to hardware reasons, it seems that it can only be reversed into the warehouse, and the accuracy is not high. In this competition, I saw that some schools use laser module recognition to judge the garage without reversing into the warehouse, For electromagnetic students can try.
(5) Summary
If someone has seen here, when you decide to do a smart car competition, I hope you can understand that the smart car competition is different from other disciplines, it requires a lot of time, and your final competition results may not be proportional to your time. In addition to time, a good teammate is also very important, He may not be the person with the most powerful hardware and software, but he must be the one who can stick with you all the time. I'm honored that I have a good teammate in this game.
Finally, when you put in a game for several months and don't achieve the results you want, you will feel a huge gap in your heart. But if someone asked me if you would regret participating in this competition, I would still say, no regret. All your competition experience will be transformed into your own achievement precipitation. Like lotus, maybe someone has bloomed the results on the water, maybe what belongs to you has not surfaced, but what is deeply buried under the mud is also your accumulated fruit. I believe it will be harvested one day. Come on, smart car man!