How to tune a line follower robot PID - Page 1
Forum section: electronics / projects

author: digitalectron
author_rank: Contributor
timestamp: November 13, 2023, 03:02:02 pm
content: Hi,This is my first post in eevblog, I’m working on a Line following robot, I’m using stm32G030K as the main controller, and I have connected 4 reflective sensors for the line position and two motor drivers for my motors, I have tried a lot to tune and write a good code so that my robot would do it’s best to follow the line and have good speed, But if I increase my motor speeds it would not follow the line Here is the main parts of the code that would do the job,checkout the robot in actionhttps://www.youtube.com/shorts/eJNDz7MstAsCode:int MyPID_kp =50, MyPID_ki = 0, MyPID_kd = 2;Calibration();while(1){MyPID_SetOutputLimits(-5000, 5000);/*Limt my PID output*/Input = Calculate_LinePosition(); /* calculate Line Position from IR Sensor*/Output = MyPID(MyPID_kp, MyPID_ki, MyPID_kd,Input);/* calculate PUD parameter*/RunMotors(Output); // send PID output to PWM for running Motor*/}After reset I would calibrate the sensors like thisCode:void Calibration(){HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // leftHAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // rightTm0 = HAL_GetTick();Tm1 = Tm0;unsigned long TmL;for (uint8_t i = 0; i < IR; i++){SenX = ReadSensors(i);MinX = SenX;MaxX = SenX;}while ((HAL_GetTick() - Tm0) <= 2000){for (uint8_t i = 0; i < IR; i++){SenX = ReadSensors(i);if (SenX < MinX)MinX = SenX;if (SenX > MaxX)MaxX = SenX;}TmL = HAL_GetTick();if ((TmL - Tm1) >= 100){Tm1 = TmL;}HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);TIM1->CCR3 = 2500; // rightHAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);TIM1->CCR4 = 500; // left}HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // leftHAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // rightHAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);TIM1->CCR3 = 0; // rightHAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);TIM1->CCR4 = 0; // left}the MyPID_SetOutputLimits would limit the PID outputCode:/*Limit my PID output*/void MyPID_SetOutputLimits(int Min, int Max){if(Min > Max) return;outMin = Min;outMax = Max;if(Output > outMax) Output = outMax;else if(Output < outMin) Output = outMin;if(ITerm> outMax) ITerm= outMax;else if(ITerm< outMin) ITerm= outMin;}I have used matlab line interpolation for finding polynomials to calculate the line position here is the function codeCode:int Calculate_LinePosition(void){Line1 = LinePosition;for (int i = 0; i < IR; i++){SenX = ReadSensors(i);// SenX = Map_Sensors(SenX, MinX, MaxX, 800, 3100);SenX = Map_Sensors(SenX, MinX, MaxX, targetMin, targetMax);SenX = Constrain_Sensors(SenX, targetMin, targetMax);}minimum = SenX;if (SenX < 3000 || SenX < 3000 || SenX < 3000){for (int i = 0; i < IR; i++){if (SenX < minimum){minimum = SenX;activeSensor = i;}}}// We obtain P1,P2,P3,P4 from basic fitting in matlab// SenX=SenX+700;if (activeSensor == 0){if (SenX > 2900){p1 = -0.010884;p2 = 35.9846;}else{p1 = 0.0092604;p2 = 23.3772;}}else if (activeSensor == 1){if (SenX < 2000){p1 = -0.0069286;p2 = 51.6287;}else{p1 = 0.0069076;p2 = 39.8585;}}else if (activeSensor == 2){if (SenX < 3000){p1 = -0.0061269;p2 = 70.4583;}else{p1 = 0.0072529;p2 = 61.0744;}}else if (activeSensor == 3){if (SenX < 2800){p1 = -0.010154;p2 = 95.2504;}else{p1 = 0.0075137;p2 = 78.6127;}}LinePosition = (p1 * SenX + p2);if (SenX > 3000 && SenX > 2800){// activeSensor = 0;}if (10 < LinePosition && LinePosition < 50){direction = 0;}else if (50 < LinePosition && LinePosition < 90){direction = 1;}if (LinePosition > 90){LinePosition = 100;}if (runLineRobot == false){}else{//if (SenX>1000 && SenX<2000 && SenX>2000&& SenX>1500){//LinePosition=50;//MODE_LEFT=true;}if (SenX > 2000 && activeSensor == 0){if (direction == 0){LinePosition = 0;}if (direction == 1){LinePosition = 100;}}return LinePosition;}the actual PID functionCode:int MyPID(int Kp, int Ki, int Kd,int input){long P = 0, I = 0, D = 0, PIDv = 0, pErr = 0;MyPID_error=Setpoint - input;P = MyPID_error;I = I + MyPID_error;D = MyPID_error - pErr;PIDv = 3 * ((Kp * MyPID_error) + (Ki * (I + MyPID_error)) + (Kd * (MyPID_error - pErr)));pErr = MyPID_error;return PIDv;}The function that would run the motorsCode:void RunMotors(int16_t OutPutPID){if (AllowMotorsRun){PIDValue = mapOutPutPID(OutPutPID, -5000, 5000, -1500, 1500);if (OutPutPID > 0){ // leftHAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // rightHAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // leftMotorLeft = 0 - PIDValue; // the power level for the A motorMotorRight = 0 - PIDValue; // the power level for the C motorSpeedLeft = BaseSpeed - PIDValue;SpeedRight = BaseSpeed + PIDValue;}else if (OutPutPID < 0){ // RightHAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // rightHAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // leftMotorLeft = PIDValue; // the power level for the A motorMotorRight = PIDValue; // the power level for the C motorSpeedLeft = BaseSpeed - PIDValue;SpeedRight = BaseSpeed + PIDValue;}else{HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3); // leftHAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_4); // rightSpeedLeft = BaseSpeed;SpeedRight = BaseSpeed;}if (SpeedLeft < SpeedMin)SpeedLeft = SpeedMin;if (SpeedLeft > SpeedMax)SpeedLeft = SpeedMax;if (SpeedRight < SpeedMin)SpeedRight = SpeedMin;if (SpeedRight > SpeedMax)SpeedRight = SpeedMax;HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); // rifhtHAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); // leftHAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); // rightHAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET); // leftBATTERY_VOLTAGE = BAT_GetVoltag(adcData);// RPM=(BATTERY_VOLTAGE-350)*0.975+150;//TIM1->CCR4 = SpeedLeft-(BATTERY_VOLTAGE-350)*0.6; // Left// TIM1->CCR3 = SpeedRight-(BATTERY_VOLTAGE-350)*0.6; // LeftTIM1->CCR4 = SpeedLeft; // LeftTIM1->CCR3 = SpeedRight; // Right}}I'm out of Ideas and I do not know what I have done wrong, do you have any Idea what I should do?

author: Terry Bites
author_rank: Super Contributor
timestamp: November 14, 2023, 10:54:16 am
content: Determine the open loop characteristic of the system and go from there.ie stimulate the controller with a short pulse and scope the motor response.D for undershoot, I for overshoot.Do you need all the PID terms? Often D is not required.I sets the damping and that may be enough.

author: Smokey
author_rank: Super Contributor
timestamp: November 14, 2023, 11:00:59 am
content: I could see how having a physical system without an absolute position feedback like that would make tuning the gains hard. For a current loop for instance, you can hook a current sensor up and watch the step response on a scope while you tweak the gains. How do you do that for a robot in the middle of the room trying to follow a line? I guess you could use an external camera pointed at the robot and some computer vision and actually quantify how much hunting/oscillation happens as it's trying to follow the line around a corner or something.

author: digitalectron
author_rank: Contributor
timestamp: November 14, 2023, 12:23:46 pm
content: QuoteHow can I do that for this robot? do you suggest any work around?QuoteI have seen many kids in robot races do this, I doubt that even one of them use Computer vision, I know it can be used, But I have lack of knowledge there, do you suggest simpler ways?

author: MarkF
author_rank: Super Contributor
timestamp: November 14, 2023, 04:10:49 pm
content: I've always struggled tuning PID controllers.Here's a little reading that might give you some insight:PID controllers (phenomenological introduction)PID controllers (analytical introduction)PID control of a 1D helicopter

author: digitalectron
author_rank: Contributor
timestamp: November 16, 2023, 08:26:47 am
content: MarkF Thanks for the links, I need some tome to study them, But if someone here that has the experience would help, I would appreciate it a lot.

author: Andy Chee
author_rank: Super Contributor
timestamp: November 16, 2023, 08:42:29 am
content: Arghh. I’m encountering similar issues PID tuning a homemade hexcopter drone!Anyway I found this video a somewhat helpful in understanding the intuitive behaviour of a system’s response to changing PID values:https://youtube.com/watch?v=qKy98CbcltwBut what is immediately helpful is having some direct physical adjustment of parameters (in the case of the video, knobs!).On a line follower robot (or drone in my case) knobs are somewhat impractical. So you need a remote control of some sort. Or you could have a PC/Mac application with on screen tuning sliders/knobs.