"Locomotion.H" "Pic32 - Ad - Lib.H" "../U8G2Headers/Common.H" "../Projectheaders/Portmap.H"
"Locomotion.H" "Pic32 - Ad - Lib.H" "../U8G2Headers/Common.H" "../Projectheaders/Portmap.H"
Module
Locomotion.c
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
#include "LOCOMOTION.h"
#include "PIC32_AD_Lib.h"
#include "../u8g2Headers/common.h"
#include "../ProjectHeaders/portmap.h"
// Hardware
#include <xc.h>
#include <proc/p32mx170f256b.h>
#include <sys/attribs.h> // for ISR macors
#include <stdlib.h>
#include <string.h>
#include <proc/p32mx170f256b.h>
#include <sys/attribs.h> // for ISR macors
//Motor Directions
#define FORWARD_DIR 1
#define REVERSE_DIR 2
#define CCW_DIR 3
/*---------------------------- Module Functions ---------------------------*/
void SPI1_LOCOMOTION_Init(void); //SPI1 INitialization
void TIMER2_INIT(void);
void PWM_RIGHT_MOTOR(void);
void PWM_LEFT_MOTOR(void);
void TIMER3_INIT(void);
void IC_INIT_ENCODER_RIGHT(void);
void IC_INIT_ENCODER_LEFT(void);
uint8_t RPM_CALC (uint16_t deltaT);
uint16_t PID_CALC_RIGHT (int16_t RPME);
uint16_t PID_CALC_LEFT (int16_t RPME);
void TIMER4_INIT(void);
void TIMER5_INIT(void);
uint8_t Command_Action (uint8_t Command);
void Motor_Direction(uint8_t Dir);
MyPriority = Priority;
//Initialize SPI
SPI1_LOCOMOTION_Init();
pinMode(RB8,OUTPUT);//STBY_HIGH
digitalWrite(RB8,HIGH);
/****************************************************************************
Function
PostFOLLOWER1
Parameters
EF_Event ThisEvent ,the event to post to the queue
Returns
bool false if the Enqueue operation failed, true otherwise
Description
Posts an event to this state machine's queue
****************************************************************************/
bool PostLOCOMOTION(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunFOLLOWER1
Parameters
* ES_Event_t ThisEvent
Returns
* ES_NO_EVENT
Description
* Initializes Pins to use for master's Commands. Replies to master's command
* and print to terminal acknowledgement of those commands
****************************************************************************/
ES_Event_t RunLOCOMOTION(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
switch(Current_State)
{
//Initialize pins RB6 for LED. RB7 for query
case INIT:
{
if(ThisEvent.EventType == ES_INIT)
{
//Initialization
TIMER3_INIT();
IC_INIT_ENCODER_RIGHT();
IC_INIT_ENCODER_LEFT();
Current_State = AWAITING_INSTRUCTIONS;
}
}
break;
//Main State of Service
case AWAITING_INSTRUCTIONS:
{
switch(ThisEvent.EventType)
{
case ES_TIMEOUT:
{
if(ThisEvent.EventParam == ZERO_RPM_RIGHT)
{CurrentRPM_RIGHT = 0;
printf("%d\r\n",CurrentRPM_RIGHT);
}
else if (ThisEvent.EventParam == ZERO_RPM_LEFT)
{CurrentRPM_LEFT = 0;
printf("%d\r\n",CurrentRPM_LEFT);
}
}
break;
case ES_XFER_COMPLETE:
{
switch(ThisEvent.EventParam)
{
case FWD:
{
Motor_Direction(FORWARD_DIR);
TargetRPM_RIGHT= 50;
TargetRPM_LEFT = 50;
}
break;
case ARC:
{
Motor_Direction(FORWARD_DIR);
TargetRPM_RIGHT= 50;
TargetRPM_LEFT = 48;
}
break;
case TIGHT_ARC:
{
Motor_Direction(FORWARD_DIR);
TargetRPM_RIGHT= 50;
TargetRPM_LEFT = TargetRPM_RIGHT*(2*10-BASE)/(2*10+BASE);
//10 is the turning radius in cm
}
break;
case TIGHT_ARC_R:
{
Motor_Direction(FORWARD_DIR);
TargetRPM_RIGHT= 2;
TargetRPM_LEFT = 50;
//0 is the turning radius in cm
}
break;
case STOP:
{
TargetRPM_RIGHT= 0;
TargetRPM_LEFT = 0;
}
break;
case REV:
{
Motor_Direction(REVERSE_DIR);
TargetRPM_RIGHT= 50;
TargetRPM_LEFT = 50;
}
break;
case TURN_IN_PLACE:
{
Motor_Direction(CCW_DIR);
TargetRPM_RIGHT= 25;
TargetRPM_LEFT = 25;
}
break;
default:{}break;
}
}
break;
default:{}break;
}
}
break;
default:{}break;
}
return ReturnEvent;
}
/***************************************************************************
private functions
***************************************************************************/
/****************************************************************************
Function
SPI1_FOLLOWER1
Parameters
* none
Returns
* none
Description
* Initializes System in slave mode with SS enabled, Enhanced
* buffer mode-8bit. RX interrupts. Uses RA0 as SS. RA1 SDI, RA2 SDO
* RB14 SCK.
****************************************************************************/
void SPI1_LOCOMOTION_Init(void){
/*-------------------------------------------------------------------------
* SS1R = RPA0 (0b0000), RA0 is INPUT
* SDI1R = RPA1 (0b0000), RA1 is INPUT
* RPA2R = SDO1 (0b0011), RA2 is OUTPUT
* RPB14R = SCK *ALWAYS, No Mapping Required*, RPB14R = INPUT
-------------------------------------------------------------------------*/
pinMode(RA0, INPUT);
pinMode(RA1, INPUT);
pinMode(RA2, OUTPUT);
pinMode(RB14, INPUT);
//Mapping
SS1R = 0b0000;
SDI1R = 0b0000;
RPA2R = 0b0011;
//Clear Overflow
SPI1STATbits.SPIROV=0;
Returns
Description
* Initializes Timer 2 using internal clock, 1:4 pre-scaler, 16 bits.
* Set frequency to 10kHz, Interrupt Disabled. Used for PWMs
****************************************************************************/
void TIMER2_INIT(void)
{
T2CONbits.ON = 0; //Disable timer for properties modification
T2CONbits.TCS = 0; //Select Internal Clock
T2CONbits.TCKPS = 0b010; //Select 1:4 Pre-scaler.
T2CONbits.T32 = 0; //Sets 16 bit timer option
TMR2 = 0; //Clears Timing to begin at 0 ticks
PR2 = 499; //sets PWM period -1 for a frequency of 10 kHz @ 20 MHz PBCLK
IFS0CLR = _IFS0_T2IF_MASK; //Clear Timer2 Flag
IEC0CLR = _IEC0_T2IE_MASK; //Disable local Interrupt
T2CONbits.ON = 1; //Re-enable Timer
Returns
Description
* Initializes Pulse WIdth Modulation using Timer 2. 16 bit. Interrupt Disabled
* Uses RB7 as output Pin. Default direction is forward
****************************************************************************/
void PWM_RIGHT_MOTOR(void)
{
RPB7R = 0b0101; //Map RB7 to OC1
//Sets motor for CW rotation
Returns
Description
* Initializes Pulse WIdth Modulation using Timer 2. 16 bit. Interrupt Disabled
* Uses RB9 as output Pin. Default direction is forward
****************************************************************************/
void PWM_LEFT_MOTOR(void)
{
RPB9R = 0b0101; //Map RB9 to OC3
Returns
Description
* Initializes Timer 3 using internal clock, 1:256 pre-scaler, 16 bits.
* Set Period to max to use in tandem with Input Capture. Interrupt Disabled.
* Used for input Capture
****************************************************************************/
void TIMER3_INIT(void)
{
T3CONbits.ON = 0; //Disable timer for properties modification
T3CONbits.TCS = 0; //Select Internal Clock
T3CONbits.TCKPS = 0b111; //Select 1:256 Pre-scaler.
//T3CONbits.T32 = 0; //Does not exist for Timer 3 or 5
TMR3 = 0; //Clears Timing to begin at 0 ticks
PR3 = 0xFFFF; //for input capture math
IFS0CLR = _IFS0_T3IF_MASK; //Clear Timer3 Flag
IEC0CLR = _IEC0_T3IE_MASK; //Disable local Interrupt
T3CONbits.ON = 1; //Re-enable Timer
}
/****************************************************************************
Function
IC_INIT_ENCODER_RIGHT
Parameters
Returns
Description
* Initializes Input Capture 2, 16 bits, using timer 3
* Interrupts on every 4th capture, beginning with rising edge first
* Priority 7. Sets Pin RA3 as Input for Capture
****************************************************************************/
void IC_INIT_ENCODER_RIGHT(void)
{
//Initializing Input Capture #2
IC2R = 0b0000; //Sets pin RA3 as Input Capture Pin
Returns
Description
* Determines Current RPM by reading Encoder Pulses. It counts the Delta
* Time between 6 pulses. Starts a 150 ms timer, which accounts for the
* motor coming to a stop.
****************************************************************************/
void __ISR(_INPUT_CAPTURE_2_VECTOR, IPL7SOFT) DC_MOTOR_ENCODER_RIGHT(void)
{
//Static Variable Declarations
volatile static uint16_t Edge[4];
static uint8_t Edge_Counter = 0;
static uint8_t Time_Counter = 0;
static uint16_t TimeStart;
Edge_Counter = 0;
ES_Timer_InitTimer(ZERO_RPM_RIGHT, 150); //Timer to Calculate if speed is 0
}
/****************************************************************************
Function
RPM_CALC
Parameters
* Delta Time
Returns
* RPM
Description
* Calculates RPM based on number of pulses read by Input Capture
****************************************************************************/
uint8_t RPM_CALC (uint16_t deltaT)
{
static uint8_t RPM;
RPM=31250/deltaT; //60*6pulses*10^7/(900ppr*130)
return RPM;
}
/****************************************************************************
Function
IC_INIT_ENCODER_LEFT
Parameters
Returns
Description
* Initializes Input Capture 4, 16 bits, using timer 3
* Interrupts on every 4th capture, beginning with rising edge first
* Priority 7. Sets Pin RB15 as Input for Capture
****************************************************************************/
void IC_INIT_ENCODER_LEFT(void)
{
//Initializing Input Capture #4
IC4R = 0b0011; //Sets pin RB15 as Input Capture Pin
Returns
Description
* Determines Current RPM by reading Encoder Pulses. It counts the Delta
* Time between 6 pulses. Starts a 150 ms timer, which accounts for the
* motor coming to a stop.
****************************************************************************/
void __ISR(_INPUT_CAPTURE_4_VECTOR, IPL7SOFT) DC_MOTOR_ENCODER_LEFT(void)
{
//Static Variable Declarations
volatile static uint16_t Edge[4];
static uint8_t Edge_Counter = 0;
static uint8_t Time_Counter = 0;
static uint16_t TimeStart;
Edge_Counter = 0;
ES_Timer_InitTimer(ZERO_RPM_LEFT, 153); //Timer to Calculate if speed is 0
}
/****************************************************************************
Function
PID_CALC
Parameters
RPM Error
Returns
Requested Duty Cycle
Description
* Establishes PID Control Law with Integral Anti-Windup
****************************************************************************/
uint16_t PID_CALC_RIGHT (int16_t RPME)
{
//Variable declarations
LastError = RPME;
return RequestedDuty;
}
/****************************************************************************
Function
PID_CALC
Parameters
RPM Error
Returns
Requested Duty Cycle
Description
* Establishes PID Control Law with Integral Anti-Windup
****************************************************************************/
uint16_t PID_CALC_LEFT (int16_t RPME)
{
//Variable declarations
LastError = RPME;
return RequestedDuty;
}
/****************************************************************************
Function
TIMER4_INIT
Parameters
Returns
Description
* Initializes Timer 4 using internal clock, 1:32 pre-scaler, 16 bits.
* Set frequency to 200 Hz, Interrupt Enabled, Priority 6.
* Will implement Control Law
****************************************************************************/
void TIMER4_INIT(void)
{
T4CONbits.ON = 0; //Disable timer for properties modification
T4CONbits.TCS = 0; //Select Internal Clock
T4CONbits.TCKPS = 0b101; //Select 1:32 Pre-scaler.
T4CONbits.T32 = 0; //Sets 16 bit timer option
TMR4 = 0; //Clears Timing to begin at 0 ticks
PR4 = 0x3124; //Period -1 for a frequency of 200 Hz @ 20 MHz PBCLK
IFS0CLR = _IFS0_T4IF_MASK; //Clear Timer4 Flag
IEC0SET = _IEC0_T4IE_MASK; //Enable local Interrupt
IPC4bits.T4IP = 0b110; //Sets Interrupt Priority to 6
IPC4bits.T4IS = 0b11; //Sets Sub-priority to 3
T4CONbits.ON = 1; //Re-enable Timer
}
/****************************************************************************
ISR TIMER 4, Priority 6
IPD_ANTI_WINDUP_UPDATE_SPEED
Parameters
Returns
Description
* Implements Control law every 5 ms. Sets OCxRS based on Control Law Output
****************************************************************************/
void __ISR(_TIMER_4_VECTOR, IPL6SOFT) IPD_ANTI_WINDUP_UPDATE_SPEED_RIGHT(void)
{
//Clearing source of the Interrupt
IFS0CLR = _IFS0_T4IF_MASK;
Returns
Description
* Initializes Timer 5 using internal clock, 1:32 pre-scaler, 16 bits.
* Set frequency to 200 Hz, Interrupt Enabled, Priority 6.
* Will implement Control Law
****************************************************************************/
void TIMER5_INIT(void)
{
T5CONbits.ON = 0; //Disable timer for properties modification
T5CONbits.TCS = 0; //Select Internal Clock
T5CONbits.TCKPS = 0b101; //Select 1:32 Pre-scaler.
//T5CONbits.T32 = 0; //Sets 16 bit timer option
TMR5 = 0; //Clears Timing to begin at 0 ticks
PR5 = 0x3124; //Period -1 for a frequency of 200 Hz @ 20 MHz PBCLK
IFS0CLR = _IFS0_T5IF_MASK; //Clear Timer4 Flag
IEC0SET = _IEC0_T5IE_MASK; //Enable local Interrupt
IPC5bits.T5IP = 0b110; //Sets Interrupt Priority to 6
IPC5bits.T5IS = 0b11; //Sets Sub-priority to 3
T5CONbits.ON = 1; //Re-enable Timer
}
/****************************************************************************
ISR TIMER 5, Priority 6
IPD_ANTI_WINDUP_UPDATE_SPEED
Parameters
Returns
Description
* Implements Control law every 5 ms. Sets OCxRS based on Control Law Output
****************************************************************************/
void __ISR(_TIMER_5_VECTOR, IPL6SOFT) IPD_ANTI_WINDUP_UPDATE_SPEED_LEFT(void)
{
//Clearing source of the Interrupt
IFS0CLR = _IFS0_T5IF_MASK;
INSTRUCTIONS.EventType = ES_XFER_COMPLETE;
INSTRUCTIONS.EventParam = Command;
PostLOCOMOTION(INSTRUCTIONS);
switch (Command)
{
case FWD:
{
return 0x0F;
}
break;
case ARC:
{
return 0x0A;
}
break;
case TIGHT_ARC:
{
return 0xAA;
}
break;
case TIGHT_ARC_R:
{
return 0xBA;
}
break;
case STOP:
{
return 0xFF;
}
break;
case REV:
{
return 0xBE;
}
break;
case TURN_IN_PLACE:
{
return 0xBB;
}
break;
default:{return 0b0;}break;
}
}
/****************************************************************************
Function
* Motor_Direction
Parameters
* uint8_t Dir
Returns
* none
Description
* set direction of the motors to go FWD, Reverse, CCW
****************************************************************************/
void Motor_Direction(uint8_t Dir)
{
if(Dir == FORWARD_DIR)
{
//Set pins for car to move forward
digitalWrite(RB5,LOW);//LOW RIGHT
digitalWrite(RB6,HIGH);//HIGH RIGHT
digitalWrite(RB12,HIGH);//HIGH LEFT
digitalWrite(RB13,LOW);//LOW LEFT
}
else if (Dir == REVERSE_DIR)
{
//Set pins for car to move in reverse
digitalWrite(RB5,HIGH);//LOW RIGHT
digitalWrite(RB6,LOW);//HIGH RIGHT
digitalWrite(RB12,LOW);//HIGH LEFT
digitalWrite(RB13,HIGH);//LOW LEFT
}
else if (Dir == CCW_DIR)
{
//Right motor forward
digitalWrite(RB5,LOW);//LOW RIGHT
digitalWrite(RB6,HIGH);//HIGH RIGHT
//Left motor reverse
digitalWrite(RB12,LOW);//HIGH LEFT
digitalWrite(RB13,HIGH);//LOW LEFT
}
}