Ajaya Dahal
Published

Simplest Line Follower Using PIC24

From 3D model to PCB design

IntermediateFull instructions provided15 hours65
Simplest Line Follower Using PIC24

Things used in this project

Hardware components

Microchip dsPIC33EP128GP
×1

Software apps and online services

MPLAB X IDE
Microchip MPLAB X IDE

Story

Read more

Custom parts and enclosures

3D model

Using Solidworks

Schematics

Schematics

Code

Code

C/C++
Upload using MPLAB X IDE
// ****************************************************************
// line_follower.c - For line follower robot 
// Author: Ajaya Dahal - ad2323@msstate.edu
// ****************************************************************

#include "pic24_all.h"

// Define the time, in us, between Timer2 and Timer3 interrupts to generate PWM of 1KHz.
#define ISR_PERIOD  (1000)

//MOTOR Enable
#define CONFIG_MOTOR1_EN() CONFIG_RB3_AS_DIG_OUTPUT()   
#define CONFIG_MOTOR2_EN() CONFIG_RB4_AS_DIG_OUTPUT()   
#define MOTOR_1_EN (_LATB3)
#define MOTOR_2_EN (_LATB4)


//left motor
#define CONFIG_MOTOR1_A()  CONFIG_RB5_AS_DIG_OUTPUT()  
#define CONFIG_MOTOR1_B()  CONFIG_RB6_AS_DIG_OUTPUT()  
#define MOTOR_1_A (_LATB5)                             
#define MOTOR_1_B (_LATB6)                             

//right_motor
#define CONFIG_MOTOR2_A()  CONFIG_RB13_AS_DIG_OUTPUT()   
#define CONFIG_MOTOR2_B()  CONFIG_RB14_AS_DIG_OUTPUT()   
#define MOTOR_2_A (_LATB13)                              
#define MOTOR_2_B (_LATB14)                              


//setup sensors
#define CONFIG_SENSOR_A()  CONFIG_RB0_AS_DIG_INPUT()  
#define CONFIG_SENSOR_B()  CONFIG_RB1_AS_DIG_INPUT()  
#define ENABLE_SENSOR_A()  ENABLE_RB0_PULLDOWN()  
#define ENABLE_SENSOR_B()  ENABLE_RB1_PULLDOWN()  

#define SENSOR_A (_RB0)
#define SENSOR_B (_RB1)


//function to move forward
void move_forward(void){
    MOTOR_1_A = 1;
    MOTOR_1_B = 0;
    MOTOR_2_A = 1;
    MOTOR_2_B = 0;
}

//function to stop motor
void stop_motors(void){
   //disable the enable pin will stop motor
    MOTOR_1_EN = 0; 
   MOTOR_2_EN = 0;
}

//function to turn left
void move_left(void){
    MOTOR_1_A = 0;
    MOTOR_1_B = 0;
    MOTOR_2_A = 1;
    MOTOR_2_B = 0;
}

//function to turn right
void move_right(void){
    MOTOR_1_A = 1;
    MOTOR_1_B = 0;
    MOTOR_2_A = 0;
    MOTOR_2_B = 0;
}

//function to move reverse  NOT IMPLEMENTED but for future use
void move_reverse(void){
    MOTOR_1_A = 1;
    MOTOR_1_B = 0;
    MOTOR_2_A = 1;
    MOTOR_2_B = 0;
}

//config motor pins
void configMotors(void){
    CONFIG_MOTOR1_EN();
    CONFIG_MOTOR2_EN();

    CONFIG_MOTOR1_A();
    CONFIG_MOTOR1_B();
    CONFIG_MOTOR2_A();
    CONFIG_MOTOR2_B();
}

//config sensor pins
void configSensors(void){
    CONFIG_SENSOR_A();
    CONFIG_SENSOR_B();
    ENABLE_SENSOR_A();
    ENABLE_SENSOR_B();
}

//create PWM for left motor
void createPWM_Left(void){
    //700+300 = 1000us = 1ms results in 1KHz PWM with 30% duty cycle. 
    if (MOTOR_1_EN == 1) {
        PR2 = usToU16Ticks(700, getTimerPrescale(T2CONbits)) - 1;  
        MOTOR_1_EN = 0;
        
    } else {
        PR2 = usToU16Ticks(300, getTimerPrescale(T2CONbits)) - 1;
        MOTOR_1_EN = 1;
    }
}

//create PWM for right motor
void createPWM_Right(void){
    //700+300 = 1000us = 1ms results in 1KHz PWM with 30% duty cycle. 
    if (MOTOR_2_EN == 1) {
        PR3 = usToU16Ticks(700, getTimerPrescale(T3CONbits)) - 1;
        MOTOR_2_EN = 0;
        
    } else {
        PR3 = usToU16Ticks(300, getTimerPrescale(T3CONbits)) - 1;
        MOTOR_2_EN = 1;
    }
}


// Interrupt Service Routine for Timer2 which is for LEFT motor
void _ISR _T2Interrupt(void) {
   createPWM_Left();
  // Clear the timer interrupt bit, signaling the PIC that this interrupt has been serviced.
  _T2IF = 0;
}

// Interrupt Service Routine for Timer3 which is for RIGHT motor
void _ISR _T3Interrupt(void) {
   createPWM_Right();
  // Clear the timer interrupt bit, signaling the PIC that this interrupt has been serviced.
  _T3IF = 0;
}

void  configTimer2(void) {
  T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
          | T2_32BIT_MODE_OFF
          | T2_SOURCE_INT
          | T2_PS_1_8;
  // Subtract 1 from ticks value assigned to PR2 because period is PRx + 1.
  PR2 = usToU16Ticks(ISR_PERIOD, getTimerPrescale(T2CONbits)) - 1;
  // Start with a cleared timer2 value.
  TMR2  = 0;
  // Enable Timer2 interrupts.
  _T2IF = 0;
  _T2IP = 1;
  _T2IE = 1;
  // Start the timer only after all timer-related configuration is complete.
  T2CONbits.TON = 1;
}

void  configTimer3(void) {
  T3CON = T3_OFF | T3_IDLE_CON | T3_GATE_OFF
          | T3_SOURCE_INT
          | T3_PS_1_8;
  // Subtract 1 from ticks value assigned to PR2 because period is PRx + 1.
  PR3 = usToU16Ticks(ISR_PERIOD, getTimerPrescale(T3CONbits)) - 1;
  // Start with a cleared timer2 value.
  TMR3  = 0;
  // Enable Timer3 interrupts.
  _T3IF = 0;
  _T3IP = 1;
  _T3IE = 1;
  // Start the timer only after all timer-related configuration is complete.
  T3CONbits.TON = 1;
}

//function that compares the sensors status and control the motor driver accordingly
void start_following(void){
    if(!SENSOR_A && !SENSOR_B){
        move_reverse();
    }
    else if(SENSOR_A && !SENSOR_B){
        move_left();
    }
    else if(!SENSOR_A && SENSOR_B){
        move_right();
    }
    else{
        move_forward();
    }
}


int main (void) {
  configBasic(HELLO_MSG);
  configMotors();
  configSensors();
  configTimer2();
  configTimer3();
  stop_motors();
  
  while (1) {
    start_following();
    DELAY_MS(20);
    stop_motors();
     // Blink the heartbeat LED to show that the PIC is running.
    doHeartbeat();
    DELAY_MS(10);
  }
}

Credits

Ajaya Dahal
11 projects • 15 followers
Electrical and Computer Engineering Certified Part 107 FAA Drone Pilot
Contact

Comments

Please log in or sign up to comment.