help with Programming a line following robot

This conference allows discussion on any subject not already covered in another PICmicro conference. If a topic becomes popular enough, a new conference will be created for it.

help with Programming a line following robot

Postby shrishi485 » Wed Dec 10, 2014 1:52 am

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 3238 times
shrishi485
 
Posts: 1
Joined: Wed Dec 10, 2014 1:44 am

Re: help with Programming a line following robot

Postby ric » Thu Dec 11, 2014 1:51 am

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.
Latest test project, an LED matrix display made from one reel of addressable LEDs. here
User avatar
ric
Verified identity
 
Posts: 454
Joined: Sat May 24, 2014 2:35 pm
Location: Melbourne, Australia
PIC experience: Professional 5+ years with MCHP products


Return to Other PICmicro topics

Who is online

Users browsing this forum: No registered users and 11 guests