Page 1 of 1

help with Programming a line following robot

PostPosted: Wed Dec 10, 2014 1:52 am
by shrishi485
I’m working on programming a line following robot which follows a black line using two sensors and when both sensors senses black at the end of the line which looks like a ’T’ the robot is supposed to turn around and follow the line back to its original spot and do the whole procedure two times. I made the robot follow the line but i need help with making it turn around. The chassis is a 6” x 61/2” board with two sensors on the bottom front and a breadboard on top with a battery pack. The sensors are about 4mm above the surface and about 2.5cm apart from each other. The black line is the width of electrical tape, so about 2 cm. A picture of the path is attached to this post. Please have a look at it and the code. Thank you very much.

Code: Select all
Hardware Notes:
 * PIC used:
 * PIC24FV32KA302 operating at 8MHz)
 * I/O ports used and hardware attached
 * Outputs:
 * RB10, RB11, RB2, RB3, RB8, RB9 connected to SN754410NE
 * RB5 and RB6 connected to left and right LEDs
 * Inputs:
 * RB15 is an analog input connected to the potentiometer
 * RB12 is an analog input connected to the left sensor
 * RB4 is an analog input connected to the right sensor
 *

 ********************************************************************/

/*******************************************************************
    Include Files
 ********************************************************************/

#include "p24FV32KA302.h"
#include "configBits.h"
#include "delay.h"

/*******************************************************************
    Symbolic Constants used by main()
 ********************************************************************/

//leave blank for now

/*******************************************************************
    Local Function Prototypes
 ********************************************************************/

void initialize();
void get_Inputs(void);
void decide(void);
void refresh_PWM(void);
void delayMs(unsigned int ms);
void line(void);

/*** Global Variable Declarations *********************************************/

unsigned int potValue; // Raw Potentiometer setting
unsigned int leftOpto; // Left Opto Sensor Signal
unsigned int rightOpto; // Right Opto Sensor Signal
unsigned int counter = 0; //Counter for when both Sensor senses black

/*** main() Function **********************************************************/

int main(void) {
    initialize();

    //infinite loop
    while (1) {
        get_Inputs();
        decide();
        refresh_PWM();
        delayMs(100);
    }

}

/*******************************************************************************
 * Function: void initialize(void)
 *
 * Overview: Initializes the microcontroller, the peripherals
 * used in the application and any global variables
 * used by multiple functions.
 *
 * Note: None
 ******************************************************************************/

void initialize(void) {
    //TRISB = 0x0000;
    //LATB = 0x0000; // digital outputs
    TRISB = 0x9010; //Initialize RB15(Potentiometer),
                    //RB12(Left Sensor) and RB4(Right Sensor) as inputs
    ANSB = 0x9010; //Initialize RB15(Potentiometer),
                   //RB12(Left Sensor) and RB4(Right Sensor) as analog inputs
    LATBbits.LATB5 = 0; //initialize output port RB5
    LATBbits.LATB6 = 0; //initialize output port RB6


    // Initialize "3-4EN" PWM control output (RB10/OC3)

    TRISBbits.TRISB10 = 0; // Make RB10 digital O/P
    LATBbits.LATB10 = 0; // initialize the pin0 voltage level

    // Initialize Output Compare 3 (OC3) to drive Motor A PWM signal to "3-4EN"
    // We want to create 61.04Hz PWM frequency @ 1024 bits resolution

    OC3CON1bits.OCM = 0b000; // Disable the OC module
    OC3R = potValue; // Write the duty cycle for the 1st PWM pulse
    OC3CON1bits.OCTSEL = 0; // Select Timer 2 as the OC time base
    OC3CON1bits.OCM = 0b110; // Select the OC mode (Edge PWM)

    // Initialize "1-2EN" PWM control output (RB11/OC2)

    TRISBbits.TRISB11 = 0; // Make RB11 digital O/P
    LATBbits.LATB11 = 0; // initialize the pin voltage level

    // Initialize Output Compare 2 (OC2) to drive Motor B PWM signal to "1-2EN"
    // We want to create 61.04Hz PWM frequency @ 1024 bits resolution

    OC2CON1bits.OCM = 0b000; // Disable the OC module
    OC2R = potValue; // Write the duty cycle for the 1st PWM pulse
    OC2CON1bits.OCTSEL = 0; // Select Timer 2 as the OC time base
    OC2CON1bits.OCM = 0b110; // Select the OC mode (Edge PWM)

    // Initialize and enable Timer 2 to create a 61.04Hz PWM frequency for both
    //PWM channels

    T2CONbits.TON = 0; // Disable Timer
    T2CONbits.TCS = 0; // Select internal instruction clock (Fosc/2)
    // which results in 8MHz/2 = 4MHz
    T2CONbits.TGATE = 0; // Disable Gated Timer Mode
    T2CONbits.TCKPS = 0b10; // Select 1:64 prescale (4MHz/64 = 62.5kHz)
    TMR2 = 0x00; // Clear timer register
    PR2 = 1024; /* Load the period register with 1024
                 * This represents the highest value that can be
                 * loaded from the pot (10-bit converted value)
                 * This forces you to choose a higher prescale.
                 * Using Fosc/2 setting = 4MHz clock
                 * choose a 1:64 prescale = 62.5kHz = .016ms period
                 * Loading the PR2 register with 1024
                 * results in a 61.04Hz control signal
                 * since 1024 * .000016s period = 16.384ms
                 * f = 1/16.384ms = 61.04Hz */

    IFS0bits.T2IF = 0; // Clear Timer 2 interrupt flag
    T2CONbits.TON = 1; // Start timer (starts PWMs)

    AD1CON1bits.ADON = 1; // Turn on ADC

    /***********************SERVO CONTROL*************************************/

  /* Initialize Output Compare 1 (OC1) to drive Servo motor using PWM signal
   * We want to create a 50Hz PWM frequency (20ms period)
   * The servo is limited from 0 to 180 degrees rotation.
   * The pulse width for this servo ranges from .75ms to 2.25ms.
   * Two Servo positions could be:
   * 0 degrees: 3.75% duty cycle (.75ms) * 10,000 = 375
   * 90 degrees: 7.5% duty cycle (1.5ms) * 10,000 = 750 */

  OC1CON1bits.OCM = 0b000; // Disable the OC module
  OC1R = 375; // Write the duty cycle for the
                                 // 1st PWM pulse at 0 degrees
  OC1CON1bits.OCTSEL = 0b001; // Select Timer 3 as the OC time base
  OC1CON1bits.OCM = 0b110; // Select the OC mode (Edge PWM)
  OC1CON2bits.SYNCSEL = 0b01101; // Synchronize OC1 to Timer3

  // Initialize and enable Timer 3 to create a 50Hz PWM frequency
  // for PWM channel

  T3CONbits.TON = 0; // Disable Timer
  T3CONbits.TCS = 0; // Select internal instruction clock (Fosc/2)
                                // which results in 8MHz/2 = 4MHz
  T3CONbits.TGATE = 0; // Disable Gated Timer Mode
  T3CONbits.TCKPS = 0b01; // Select 1:8 prescale (4MHz/8 = 500kHz)
  TMR3 = 0x00; // Clear timer register
  PR3 = 10000; /* Load the period register needed for
                                 * for 50Hz (20ms) control signal.
                                 * Using Fosc/2 setting = 4MHz clock
                                 * snd 1:8 prescale = 500kHz = 0.02ms period
                                 * 10,000 clock cycles needed (20ms/0.02ms) */

  IFS0bits.T3IF = 0; // Clear Timer 3 interrupt flag
  T3CONbits.TON = 1; // Start timer (starts PWMs)

}

/*******************************************************************************
 * Function: void get_Inputs(void)
 *
 * Overview: Obtains any input information either on-chip
 * (from internal registers, etc...) or off-chip
 * (pin voltage levels). Uses this information to modify
 * or update special data structures used in the control
 * function "decide()"
 *
 * Note: None
 ******************************************************************************/

void get_Inputs(void) {

    // Sample/convert/save Opto Sensor and Pot Levels

    // Left

    AD1CHS = 0x000C; // Connect AN15(RB4) as CH0 input
    AD1CON1bits.SAMP = 1; // Sample potentiometer value
    delayMs(5); // after 5mS start conversion
    AD1CON1bits.SAMP = 0; // Convert potentiometer value
    while (!AD1CON1bits.DONE); // conversion done? (takes 12*Tad)
    leftOpto = ADC1BUF0; // yes, then save ADC value

    // Right

    AD1CHS = 0x000F; // Connect AN12(RB12) as CH0 input
    AD1CON1bits.SAMP = 1; // Sample potentiometer value
    delayMs(5); // after 5mS start conversion
    AD1CON1bits.SAMP = 0; // Convert potentiometer value
    while (!AD1CON1bits.DONE); // conversion done? (takes 12*Tad)
    rightOpto = ADC1BUF0; // yes, then save ADC value

    // Sample/save potentiometer connected to RA0/AN0

    AD1CHS = 0x0009; // Connect ANSB15(RB15) as CH0 input
    AD1CON1bits.SAMP = 1; // Sample potentiometer value
    delayMs(1); // after 1mS start conversion
    AD1CON1bits.SAMP = 0; // Convert potentiometer value
    while (!AD1CON1bits.DONE); // conversion done? (takes 12*Tad)
    potValue = ADC1BUF0; // yes, then save ADC value

}

/*******************************************************************************
 * Function: void decide(void)

 * Overview: Makes decisions based on the input information
 * gathered in get_Inputs() function to manipulate
 * global output control variables.
 *
 * Note: None
 ******************************************************************************/

void decide(void) {

    if (leftOpto < 145) { //Left sensor senses black, turns left
        LATBbits.LATB5 = 1;
        PORTBbits.RB2 = 0;
    }
    else
    {
        LATBbits.LATB5 = 0;
        PORTBbits.RB2 = 1;
    }
    if (rightOpto < 145) //Right sensor sense black, turns right
    {
        LATBbits.LATB6 = 1;
        PORTBbits.RB8 = 0;
    } else
    {
        LATBbits.LATB6 = 0;
        PORTBbits.RB8 = 1;
    }
    if (leftOpto < 145 && rightOpto < 145) {
        counter++;
        line();
    }
}

/*******************************************************************************
 * Function: void refresh_PWM(void)

 * Overview: Based on the decisions made in the previous function,
 * this function updates the speed of the motors
 *
 * Note: None
 ******************************************************************************/

void refresh_PWM(void) {
    // Update PWM duty cycle registers (motor speed/torque) for both motors
    OC3R = potValue;
    OC2R = potValue;
}

/*******************************************************************************
 * Function: void delayMs(unsigned int ms)
 *
 * PreCondition: Requires Tcyc=250nS (8 MHz Fosc)
 *
 * Input: delay in milliseconds (1-65535)
 *
 * Output: None
 *
 * Side Effects: Blocking Delay (CPU is blocked from doing other tasks)
 * Non-portable (Uses PIC24 Assembly language instructions)
 *
 * Overview: This function implements an in-line delay of up to 65535ms
 *
 * Note: None
 ******************************************************************************/

void delayMs(unsigned int ms) {
    while (ms--) {
        asm("repeat #4000"); // 4000 instruction cycles @ 250nS ea. = 1mS
        asm("nop"); // instruction to be repeated 4000x
    }

}

void line(void) {
    if (counter == 0)
    {
        refresh_PWM();

        PORTBbits.RB2 = 1; //Ignore the first time both sensor senses black and
                           //keep going
        PORTBbits.RB8 = 1;
        delayMs(500);
        counter++;

    }
    else if (counter == 4) {

        PORTBbits.RB2 = 0;//Ignore the second time both sensor senses black and
                          //keep going
        PORTBbits.RB8 = 0;

    }
    else
    {
        PORTBbits.RB2 = 0;//Stop and turn the servo
        PORTBbits.RB9 = 0;
        OC1R = 1125;
// the code below is supposed to turn the robot but it doesnt. the robot keeps turning and doesnt follow the line back

// PORTBbits.RB2 = 1;//Turn around
// PORTBbits.RB9 = 1;
// delayMs(2000);
// do
// {
// PORTBbits.RB2 = 0;//Turn around
// PORTBbits.RB9 = 0;
// decide();
// }
// while(leftOpto < 145 || rightOpto < 145);
// do
// {
// PORTBbits.RB2 = 1;//Turn around
// PORTBbits.RB9 = 1;
// }
// while(leftOpto > 145 && rightOpto > 145);
//
//
//
// do{
// PORTBbits.RB2 = 0;//Turn around
// PORTBbits.RB9 = 0;
// decide();
// }
// while(leftOpto < 145 || rightOpto < 145);
// while (1)
// {
// if(leftOpto > 145 && rightOpto > 145)
// {
// PORTBbits.RB2 = 1;//Turn around
// PORTBbits.RB9 = 1;
// }
// else
// break;
// }
// decide();
// }
}
}


6.gif
6.gif (49.8 KiB) Viewed 9222 times

Re: help with Programming a line following robot

PostPosted: Thu Dec 11, 2014 1:51 am
by ric
Topic moved from "In Circuit Serial Programming" to "Other PICmicro topics".
Just because a topic title includes the word "programming" doesn't mean it is a general programming discussion forum.

This question comes from http://www.microchip.com/forums/m836321.aspx
you will find pretty much the same people answering here, so there's not much to be gained by opening a parallel topic.

Note, your topic is in the wrong forum there. I purposely renamed the forum here to try to make sure people didn't make the same mistake.