0% found this document useful (0 votes)
15 views

Controls Lab

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

Controls Lab

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

Control Systems Lab -

Experiment 3 Line
follower using
SPARKV
Group Number 16
Aviral Vishesh Goel, 22B2156
Siddick Khatri, 22b4241
Samarth Sirsat, 22b3988
October 24, 2024

1
1 AIM

To design and implement a PID controller for the Spark V robot that allows it to
follow a continuous black track, the IR sensors on the robot will be used for
feedback. The objective is to tune the PID parameters so that the robot completes the
track in under 30 seconds.

The Spark V robot is powered by an ATMEGA16 microcontroller, which can be


programmed using the AVR Programmer tool in Embedded C. The robot supports
eight different movement modes by altering the register values.

For this particular task, we will only use the LEFT and RIGHT movement commands
in the algorithm. Speed control is managed using Pulse Width Modulation (PWM).
The robot is equipped with three IR sensors beneath its chassis, each providing a
reading between 0 and 255 based on the surface reflectivity.

2 Arduino Code
// -O0
// 7372800Hz

#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;
const int P=6;
const int I;
const int D= 1;
const int t1=0;

void motion_pin_config (void)


{
DDRB = DDRB | 0x0F; //set direction of the PORTB3 to PORTB0 pins as output

2
PORTB = PORTB & 0xF0; // set initial value of the PORTB3 to PORTB0 pins to
logic 0
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
restoring the PORTB status
PORTB = PortBRestore; // setting the command to the port
}

void forward (void) //both wheels forward


{
motion_set(0x06);
OCR1AL = 0x8F;
OCR1BL = 0x8F;
}

void back (void) //both wheels backward


{
motion_set(0x09);
}

void left (int control_signal) //Left wheel backward, Right wheel forward
{
if(control_signal>255) control_signal=255;
motion_set(0x05);
//OCR1BL = control_signal/100;
//OCR1AL = control_signal/100;
OCR1BL = control_signal;
OCR1AL = control_signal;
}

void right (int control_signal) //Left wheel forward, Right wheel backward
{

3
if(control_signal>205) control_signal=135;
motion_set(0x0A);
OCR1BL = control_signal +120;
OCR1AL = control_signal+
120;
}

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


{
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

4
}

void init_devices (void)


{
cli(); //Clears the global interrupts
port_init();
adc_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)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xFF; //setup
TCNT1L = 0x01;
OCR1AH = 0x00;

5
OCR1AL = 0x7F; //speedleft
OCR1BH = 0x00;
OCR1BL = 0x7F;
ICR1H = 0x00;
ICR1L = 0xFF;
TCCR1A = 0xA1;
TCCR1B = 0x0D; //start Timer
}

//This Function accepts the Channel Number and returns the corresponding
Analog Value
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;
}

//Main Function
int main(void)
{
init_devices();

lcd_set_4bit();
lcd_init();
int control_signal,erro,diff;
int prev_erro=0;
int odd=0;
timer1_init();
while(1)
{
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(r>15 && l>15){

6
forward();
}
if(r<10 && c<10 && l<10){
forward();
_delay_ms(300);
}
else if(r-c>t1){
erro=r-c;
if(erro==prev_erro){forward();
continue;}
diff=erro-prev_erro;
control_signal=(P*erro)-(D*diff);
if(diff>55){
soft_stop();
}
else{
right(control_signal);
}
}
else if(l-c>t1){
erro=l-c;
if(erro==prev_erro){forward();
continue;}
diff=erro-prev_erro;
control_signal=(P*erro)-(D*diff);
if(diff>60){
soft_stop();
}
else{
left(control_signal);
}
}
else{
if(r>50 && l>50){
soft_stop();
}
else{motion_set(0x06);}
}
prev_erro=erro;

_delay_ms(25);

/* forward(); //both wheels forward


_delay_ms(1000);

7
hard_stop();
_delay_ms(300);

back(); //both wheels backward


_delay_ms(1000);

hard_stop();
_delay_ms(300);

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


_delay_ms(1000);*/

// hard_stop();
// _delay_ms(300);
//
// right(); //Left wheel forward, Right wheel backward
// _delay_ms(1000);
//
// hard_stop();
// _delay_ms(300);
//
// soft_left(); //Left wheel stationary, Right wheel forward
// _delay_ms(1000);
//
// hard_stop();
// _delay_ms(300);
//
// soft_right(); //Left wheel forward, Right wheel is stationary
// _delay_ms(1000);
//
// hard_stop();
// _delay_ms(300);
//
// soft_left_2(); //Left wheel backward, right wheel stationary
// _delay_ms(1000);
//
// hard_stop();
// _delay_ms(300);
//
// soft_right_2(); //Left wheel stationary, Right wheel backward
// _delay_ms(1000);
//
// hard_stop();

8
// _delay_ms(300);
}

3 Challenges Faced and their Solutions


• As mentioned earlier one of the major challenges was to cross the plus
shaped obstacles on the path of the bot. We had to go through a lot of ways
to get this done right.

• We made a crucial mistake of not noting the sensor values across the
different regions of the track. Because of this we faced a lot of issues in
tuning the PID parameters.

• The bot allotted to our team had one faulty center which always lead the bot
to prefer one side more than needed using the turns.

4 Results
• P=6

• D=1

• I=0

• total time taken to complete the path = 27.1 seconds

5 Observations and Inference


• Increasing the value of Kp increases the speed of the bot.

• Adding the derivative term to the controller reduced these oscillations and
then the system met the required track.

You might also like