You are on page 1of 10

EE234: Controls Lab

Experiment 2
Group 1, Friday Batch

Siddhant Chourasia (210070085)


Yogesh Sahu (210070098)
Vikas Kumar (210070093)

Contents
1 Objectives 2

2 Control Algorithm 2
2.1 Methodology . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2 Theory (PID Controller) . . . . . . . . . . . . . . . . . . . . . 2
2.3 Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

3 Challenges Faced 9

4 Observations and Results 10


4.1 Observations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.2 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

1
1 Objectives
• To design a PID controller for the Spark V robot to make it follow a
the track using IR sensors

• To complete the track from start to finish within 30 seconds

2 Control Algorithm
2.1 Methodology
Following are the steps we followed:

1. The readings of the IR sensors were used to compute the error term.

2. The output of the controller function as according to the error gives us


the desired direction and motion by altering the left and right motor
speeds independently.

3. Suppose the PID output is greater than some threshold it performs


the right turn, similarly for straight and left motions, with the velocity
being directly controlled using this PID controller output using PWM.

2.2 Theory (PID Controller)


The error that we deal with is

e(t) = Reading from the Right IR Sensor - Reading from the Left IR Sensor
This error helps us determine the speed of the motors.

The proportional term is responsible for providing an immediate response to


the current error. If the Kp gain is too high, it can lead to oscillations and
instability as the robot might overshoot the line.

The integral term basically adds up the past errors and multiplies them by
a constant (Ki ) to produce a correction term. This would help us counter
small and consistent errors.

2
The derivative term is an estimate of the future trend of the error based on its
current rate of change (Kd * rate of change of error). It acts as a dampening
mechanism to reduce overshooting and oscillations caused by rapid changes
in error. It basically prevents the robot from making sudden corrections.

Thus every response has its own significance and can be used as a combina-
tion to build a stable control system.

The Control Function is:


Z t
d(e(t)
cout (t) = Kp · e(t) + Ki · e(τ ) dτ + Kd ·
0 dt

The following function is further used to control our motor speeds

velocity = velocity(basespeed − vf ∗ cout (t), basespeed + vf ∗ cout (t))

where Kp , Ki , Kd , vf are all non-negative, and denote the coefficients for the
proportional, integral, and derivative terms, and scaling for Cout respectively

2.3 Code
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd.c"

unsigned char ADC_Conversion(unsigned char);


unsigned char ADC_Value;
unsigned char l = 0;
unsigned char c = 0;
unsigned char r = 0;
unsigned char PortBRestore = 0;

void motion_pin_config (void)


{
DDRB = DDRB | 0x0F; //set direction of the PORTB3 to PORTB0 pins as output
PORTB = PORTB & 0xF0; // set initial value of the PORTB3 to PORTB0 pins to logic

3
DDRD = DDRD | 0x30; //Setting PD4 and PD5 pins as output for PWM generation
PORTD = PORTD | 0x30; //PD4 and PD5 pins are for velocity control using PWM
}

//Function used for setting motor’s direction


void motion_set (unsigned char Direction)
{
unsigned char PortBRestore = 0;

Direction &= 0x0F; // removing upper nibbel as it is not needed


PortBRestore = PORTB; // reading the PORTB’s original status
PortBRestore &= 0xF0; // setting lower direction nibbel to 0
PortBRestore |= Direction; // adding lower nibbel for direction command and rest
PORTB = PortBRestore; // setting the command to the port
}

void forward (void) //both wheels forward


{
motion_set(0x06);
}

void back (void) //both wheels backward


{
motion_set(0x09);
}

void left (void) //Left wheel backward, Right wheel forward


{
motion_set(0x05);
}

void right (void) //Left wheel forward, Right wheel backward


{
motion_set(0x0A);
}

void soft_left (void) //Left wheel stationary, Right wheel forward


{

4
motion_set(0x04);
}

void soft_right (void) //Left wheel forward, Right wheel is stationary


{
motion_set(0x02);
}

void soft_left_2 (void) //Left wheel backward, right wheel stationary


{
motion_set(0x01);
}

void soft_right_2 (void) //Left wheel stationary, Right wheel backward


{
motion_set(0x08);
}

void hard_stop (void) //hard stop(stop suddenly)


{
motion_set(0x00);
}

void soft_stop (void) //soft stop(stops slowly)


{
motion_set(0x0F);
}

//Function to Initialize ADC


void adc_init()
{
ADCSRA = 0x00;
ADMUX = 0x20; //Vref=5V external --- ADLAR=1 --- MUX4:0 = 0000
ACSR = 0x80;
ADCSRA = 0x86; //ADEN=1 --- ADIE=1 --- ADPS2:0 = 1 1 0
}

5
void init_devices (void)
{
cli(); //Clears the global interrupts
port_init();
adc_init();
timer1_init();
sei(); //Enables the global interrupts
}

//Function to configure LCD port


void lcd_port_config (void)
{
DDRC = DDRC | 0xF7; //all the LCD pin’s direction set as output
PORTC = PORTC & 0x80; // all the LCD pins are set to logic 0 except PORTC 7
}

//ADC pin configuration


void adc_pin_config (void)
{
DDRA = 0x00; //set PORTF direction as input
PORTA = 0x00; //set PORTF pins floating
}

//Function to Initialize PORTS


void port_init()
{
lcd_port_config();
adc_pin_config();
motion_pin_config();
}

//TIMER1 initialize - prescale:64


// WGM: 5) PWM 8bit fast, TOP=0x00FF
// desired value: 450Hz
// actual value: 450.000Hz (0.0%)
void timer1_init(void)
{

6
TCCR1B = 0x00; //stop
TCNT1H = 0xFF; //setup
TCNT1L = 0x01;
OCR1AH = 0x00;
OCR1AL = 0xFF;
OCR1BH = 0x00;
OCR1BL = 0xFF;
ICR1H = 0x00;
ICR1L = 0xFF;
TCCR1A = 0xA1;
TCCR1B = 0x0D; //start Timer
}

//This Function accepts the Channel Number and returns the corresponding Analog Va
unsigned char ADC_Conversion(unsigned char Ch)
{
unsigned char a;
Ch = Ch & 0x07;
ADMUX= 0x20| Ch;
ADCSRA = ADCSRA | 0x40; //Set start conversion bit
while((ADCSRA&0x10)==0); //Wait for ADC conversion to complete
a=ADCH;
ADCSRA = ADCSRA|0x10; //clear ADIF (ADC Interrupt Flag) by writing 1 to it
return a;
}

void speed(unsigned char left_moto, unsigned char right_moto){


OCR1AL = left_moto;
OCR1BL = right_moto;
}

//Main Function
int main(void)
{
init_devices();
//speed(100,100);

lcd_set_4bit();

7
lcd_init();
int kp = 40;
int ki = 0.005;
int kd = 35;
int pre = 0;
int total = 0;
int turn = 20;

while(1)
{
total += l-r;
l=ADC_Conversion(3);
c=ADC_Conversion(4);
r=ADC_Conversion(5);
lcd_print(1, 1, l, 3);
lcd_print(1, 5, c, 3);
lcd_print(1, 9, r, 3);

if(l < 8 && r< 8 && c < 8){


forward();
speed(150,150);
_delay_ms(1000);
}
else if(l-r>=3){
left();

speed(((turn+kp*abs(l-r) + ki*total+ kd*(abs(l-r)-pre))>150)? 150 : (turn+kp*abs(l


;
//speed(20,20);
}
else if( r-l >=3) {right();

speed(((turn+kp*abs(l-r) + ki*total+ kd*(abs(l-r)-pre))>150)? 150 : (turn+kp*abs(l


;
}
else{
forward();
speed(150,150);

8
}
pre = total;
_delay_ms(10);
}

3 Challenges Faced
1. IR sensor calibration
There was a mitchmatch in the readings of the IR sesnors, and we had
to calibrate these readings by tuning the potentiometers. After getting
the left and right sensor values were nearly same, and we implemented
the conditional code accordingly

2. Hyperparameter tuning
We had to fine tune the base speed, by trail and error. We then had to
tune the values of Kp , Ki &Kd to get the best results. In the end, after
making sure the bot completes the track without getting out of track
anywhere, we adjusted the base speed again, so that the bot finishes
the track in given time.

3. Junction Turns
Initially, our bot failed at sharp turns, as the sensing required more
time. We resolved this problem by reducing the base speed. At junc-
tions, the bot used to take left/right turns instead of going forward. We
resolved this issue by firstly identifying the junction point is reached,
and then giving a delay while going forward. No condition other than
forward movement is executed for the set delay. Hence, the bot moved
in the desired direction at junctions.

4. Overheating of the motors


We made a mistake by not putting an upper limit to the bot speed
value. As our code allowed the bot to gain higher and higher speeds,
whereas the maximum it can actually attain was 255, the motors over-
heated. This problem was resolved by putting an upper limit in our
calculations.

9
4 Observations and Results
4.1 Observations
• Increasing Kp made the bot more responsive at turns but made more
oscillations and overshoots.
• With proper tuning of the base-speed many challenges faced were solved.
• A higher base speed would cause turns to be missed.
• A lower base speed would cause over time.

4.2 Results
Following are the values of Kp , Ki & Kd :

• Kp : 40

• Ki : 35

• Kd : 0.005

Our bot completed the track in 25s, and it faced no problems in finishing
the track in time.

10

You might also like