Austin Community College initial line follower program for Freescale car. This is based upon the FRDM-TFC code at mbed.org.
Fork of FRDM-TFC by
Austin Community College - Initial Specs for FRDM-TFC line following car.
This uses the fine library by ELI HUGHES.
Our goal here is to provide the simplest line-follower as a quick car checkout.
First, we limit the run duration for the car, so that you can catch it, if necessary. Right DIP switch (4) sets run time. 0 => 5 sec, 1 => 10 sec.
We provide simple speed selection with the other three DIP switches. I recommend 001 as the slowest real speed, (000 is stop, of course). DIP switches 1 2 3 make a 3 bit speed. 1 is msb, 3 is lsb
The car won't start until you press and release the driver's side PB. Left PB (TFC_PUSH_BUTTON_1) is permissive GO on release using left 3 DIPs for speed 0-7.
The car will stop when the passenger side PB is pressed. Right PB is STOP - TFC_PUSH_BUTTON_0
TFC_Ticker[3] is our run time counter. Like the Code Warrior edition, we use msec tickers.
Left (Driver side) trim pot 1 can be used to trim static steering servo Right trim pot 0 can be used to offset line camera
Back LED reflects drive motor status. The top three are not currently used.
main.cpp@5:9d36b4c896e1, 2013-11-11 (annotated)
- Committer:
- knalty
- Date:
- Mon Nov 11 03:04:42 2013 +0000
- Revision:
- 5:9d36b4c896e1
- Parent:
- 4:8a4a3fc59e57
Initial Line Following Code, Nov 10, 2013
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
emh203 | 3:23cce037011f | 1 | #include "mbed.h" |
emh203 | 3:23cce037011f | 2 | #include "TFC.h" |
emh203 | 3:23cce037011f | 3 | |
knalty | 5:9d36b4c896e1 | 4 | |
knalty | 5:9d36b4c896e1 | 5 | /* Austin Community College Initial Specs |
knalty | 5:9d36b4c896e1 | 6 | |
knalty | 5:9d36b4c896e1 | 7 | Left (Driver side) trimpot 1 can be used to trim static steering servo |
knalty | 5:9d36b4c896e1 | 8 | |
knalty | 5:9d36b4c896e1 | 9 | Right trimpot 0 can be used to offset line camera |
knalty | 5:9d36b4c896e1 | 10 | |
knalty | 5:9d36b4c896e1 | 11 | Left PB (TFC_PUSH_BUTTON_1) is permissive GO using left 3 DIPs for speed 0-7 |
emh203 | 3:23cce037011f | 12 | |
knalty | 5:9d36b4c896e1 | 13 | Right DIP switch (4) sets run time. 0 => 5 sec, 1 => 10 sec. |
knalty | 5:9d36b4c896e1 | 14 | DIP switches 1 2 3 make a 3 bit speed. 1 is msb, 3 is lsb |
knalty | 5:9d36b4c896e1 | 15 | TFC_Ticker[3] is our run time counter |
knalty | 5:9d36b4c896e1 | 16 | |
knalty | 5:9d36b4c896e1 | 17 | Right PB is STOP and CENTER_SERVO. TFC_PUSH_BUTTON_0 |
emh203 | 3:23cce037011f | 18 | |
knalty | 5:9d36b4c896e1 | 19 | Back LED reflects drive motor status |
knalty | 5:9d36b4c896e1 | 20 | |
knalty | 5:9d36b4c896e1 | 21 | */ |
knalty | 5:9d36b4c896e1 | 22 | |
knalty | 5:9d36b4c896e1 | 23 | |
knalty | 5:9d36b4c896e1 | 24 | //This ticker code is used to maintain compability with the Codewarrior version of the sample. |
knalty | 5:9d36b4c896e1 | 25 | // This code uses an MBED Ticker for background timing. |
knalty | 5:9d36b4c896e1 | 26 | |
emh203 | 3:23cce037011f | 27 | //This ticker code is used to maintain compability with the Codewarrior version of the sample. This code uses an MBED Ticker for background timing. |
emh203 | 3:23cce037011f | 28 | |
emh203 | 3:23cce037011f | 29 | #define NUM_TFC_TICKERS 4 |
emh203 | 3:23cce037011f | 30 | |
emh203 | 3:23cce037011f | 31 | Ticker TFC_TickerObj; |
emh203 | 3:23cce037011f | 32 | |
emh203 | 3:23cce037011f | 33 | volatile uint32_t TFC_Ticker[NUM_TFC_TICKERS]; |
emh203 | 3:23cce037011f | 34 | |
emh203 | 3:23cce037011f | 35 | void TFC_TickerUpdate() |
emh203 | 3:23cce037011f | 36 | { |
emh203 | 3:23cce037011f | 37 | int i; |
emh203 | 3:23cce037011f | 38 | |
emh203 | 3:23cce037011f | 39 | for(i=0; i<NUM_TFC_TICKERS; i++) |
emh203 | 3:23cce037011f | 40 | { |
emh203 | 3:23cce037011f | 41 | if(TFC_Ticker[i]<0xFFFFFFFF) |
emh203 | 3:23cce037011f | 42 | { |
emh203 | 3:23cce037011f | 43 | TFC_Ticker[i]++; |
emh203 | 3:23cce037011f | 44 | } |
emh203 | 3:23cce037011f | 45 | } |
emh203 | 3:23cce037011f | 46 | } |
emh203 | 3:23cce037011f | 47 | |
emh203 | 3:23cce037011f | 48 | |
emh203 | 3:23cce037011f | 49 | |
emh203 | 3:23cce037011f | 50 | |
emh203 | 3:23cce037011f | 51 | |
knalty | 5:9d36b4c896e1 | 52 | int main(void) |
knalty | 5:9d36b4c896e1 | 53 | { |
knalty | 5:9d36b4c896e1 | 54 | uint32_t i=0; |
knalty | 5:9d36b4c896e1 | 55 | uint32_t MaxRunTime; |
knalty | 5:9d36b4c896e1 | 56 | uint8_t Motor_ON; |
knalty | 5:9d36b4c896e1 | 57 | float Motor_Speed; |
knalty | 5:9d36b4c896e1 | 58 | float Servo_Position; // -1.0 .. +1.0 |
knalty | 5:9d36b4c896e1 | 59 | float Servo_Offset; // -1.0 to +1.0 |
knalty | 5:9d36b4c896e1 | 60 | float Camera_Offset; |
knalty | 5:9d36b4c896e1 | 61 | uint8_t Start_PB_Pressed; // flag to detect release of Start_PB |
knalty | 5:9d36b4c896e1 | 62 | uint8_t DIP_Speed; |
knalty | 5:9d36b4c896e1 | 63 | uint8_t scratch; |
knalty | 5:9d36b4c896e1 | 64 | uint16_t Current_Location; |
knalty | 5:9d36b4c896e1 | 65 | uint16_t Current_Min; |
knalty | 5:9d36b4c896e1 | 66 | float DarkSpot; |
knalty | 5:9d36b4c896e1 | 67 | |
knalty | 5:9d36b4c896e1 | 68 | // Initialization |
knalty | 5:9d36b4c896e1 | 69 | |
knalty | 5:9d36b4c896e1 | 70 | TFC_Init(); |
knalty | 5:9d36b4c896e1 | 71 | TFC_TickerObj.attach_us(&TFC_TickerUpdate,1000); |
knalty | 5:9d36b4c896e1 | 72 | |
knalty | 5:9d36b4c896e1 | 73 | TFC_HBRIDGE_DISABLE; // Explicitly turn off motor |
knalty | 5:9d36b4c896e1 | 74 | TFC_SetMotorPWM(0.0, 0.0 ); // Explicitly zero motor setpoints |
knalty | 5:9d36b4c896e1 | 75 | TFC_SetServo(0, 0.0); // Explicitly center steering servo |
knalty | 5:9d36b4c896e1 | 76 | Motor_ON = 0; |
knalty | 5:9d36b4c896e1 | 77 | Motor_Speed = 0; |
knalty | 5:9d36b4c896e1 | 78 | Start_PB_Pressed = 0; |
knalty | 5:9d36b4c896e1 | 79 | Servo_Position = 0.0; |
knalty | 5:9d36b4c896e1 | 80 | TFC_BAT_LED0_OFF; |
knalty | 5:9d36b4c896e1 | 81 | TFC_BAT_LED1_OFF; |
knalty | 5:9d36b4c896e1 | 82 | TFC_BAT_LED2_OFF; |
knalty | 5:9d36b4c896e1 | 83 | TFC_BAT_LED3_OFF; |
knalty | 5:9d36b4c896e1 | 84 | DIP_Speed = 0; |
knalty | 5:9d36b4c896e1 | 85 | TFC_Ticker[3] = 0; // clear run timer |
knalty | 5:9d36b4c896e1 | 86 | |
knalty | 5:9d36b4c896e1 | 87 | // Main Event Loop |
knalty | 5:9d36b4c896e1 | 88 | |
knalty | 5:9d36b4c896e1 | 89 | for(;;) |
knalty | 5:9d36b4c896e1 | 90 | { |
knalty | 5:9d36b4c896e1 | 91 | |
knalty | 5:9d36b4c896e1 | 92 | //TFC_Task coordinates with communications and periodic interrupt routines |
knalty | 5:9d36b4c896e1 | 93 | |
knalty | 5:9d36b4c896e1 | 94 | // TFC_Task(); |
knalty | 5:9d36b4c896e1 | 95 | |
knalty | 5:9d36b4c896e1 | 96 | // check for stop button pressed |
knalty | 5:9d36b4c896e1 | 97 | |
knalty | 5:9d36b4c896e1 | 98 | if (TFC_PUSH_BUTTON_0_PRESSED) |
knalty | 5:9d36b4c896e1 | 99 | { |
knalty | 5:9d36b4c896e1 | 100 | TFC_HBRIDGE_DISABLE; // Explicitly turn off motor |
knalty | 5:9d36b4c896e1 | 101 | TFC_SetMotorPWM(0.0, 0.0 ); // Explicitly zero motor setpoints |
knalty | 5:9d36b4c896e1 | 102 | TFC_SetServo(0, 0.0); // Explicitly center steering servo |
knalty | 5:9d36b4c896e1 | 103 | Motor_ON = 0; |
knalty | 5:9d36b4c896e1 | 104 | Motor_Speed = 0.0; |
knalty | 5:9d36b4c896e1 | 105 | Start_PB_Pressed = 0; |
knalty | 5:9d36b4c896e1 | 106 | Servo_Position = 0.0; |
knalty | 5:9d36b4c896e1 | 107 | TFC_BAT_LED0_OFF; // turn off motor power indicator LED |
knalty | 5:9d36b4c896e1 | 108 | TFC_BAT_LED1_OFF; |
knalty | 5:9d36b4c896e1 | 109 | TFC_BAT_LED2_OFF; |
knalty | 5:9d36b4c896e1 | 110 | TFC_BAT_LED3_OFF; |
knalty | 5:9d36b4c896e1 | 111 | |
knalty | 5:9d36b4c896e1 | 112 | } |
knalty | 5:9d36b4c896e1 | 113 | |
knalty | 5:9d36b4c896e1 | 114 | // read trimpots to establish servo and camera offsets |
knalty | 5:9d36b4c896e1 | 115 | |
knalty | 5:9d36b4c896e1 | 116 | Camera_Offset = TFC_ReadPot(0); // returns -1.0 to 1.0 |
knalty | 5:9d36b4c896e1 | 117 | Servo_Offset = TFC_ReadPot(1); // returns -1.0 to 1.0 |
knalty | 5:9d36b4c896e1 | 118 | |
knalty | 5:9d36b4c896e1 | 119 | // read SW4 and update MaxRunTime |
knalty | 5:9d36b4c896e1 | 120 | |
knalty | 5:9d36b4c896e1 | 121 | if (TFC_GetDIP_Switch() & 8) MaxRunTime = 10000; else MaxRunTime = 5000; // 10 sec, or 5 sec |
knalty | 5:9d36b4c896e1 | 122 | |
knalty | 5:9d36b4c896e1 | 123 | // check run status, and turn off motors if run time exceeded |
knalty | 5:9d36b4c896e1 | 124 | |
knalty | 5:9d36b4c896e1 | 125 | if (Motor_ON == 0) TFC_Ticker[3] = 0; // clear run timer |
knalty | 5:9d36b4c896e1 | 126 | else if(TFC_Ticker[3] > MaxRunTime) |
knalty | 5:9d36b4c896e1 | 127 | { |
knalty | 5:9d36b4c896e1 | 128 | TFC_HBRIDGE_DISABLE; // Explicitly turn off motor |
knalty | 5:9d36b4c896e1 | 129 | TFC_SetMotorPWM(0.0, 0.0 ); // Explicitly zero motor setpoints |
knalty | 5:9d36b4c896e1 | 130 | TFC_SetServo(0, 0.0); // Explicitly center steering servo |
knalty | 5:9d36b4c896e1 | 131 | Motor_ON = 0; |
knalty | 5:9d36b4c896e1 | 132 | Motor_Speed = 0.0; |
knalty | 5:9d36b4c896e1 | 133 | Start_PB_Pressed = 0; |
knalty | 5:9d36b4c896e1 | 134 | Servo_Position = 0.0; |
knalty | 5:9d36b4c896e1 | 135 | TFC_BAT_LED0_OFF; // turn off motor power indicator LED |
knalty | 5:9d36b4c896e1 | 136 | TFC_BAT_LED1_OFF; |
knalty | 5:9d36b4c896e1 | 137 | TFC_BAT_LED2_OFF; |
knalty | 5:9d36b4c896e1 | 138 | TFC_BAT_LED3_OFF; |
knalty | 5:9d36b4c896e1 | 139 | } |
knalty | 5:9d36b4c896e1 | 140 | |
knalty | 5:9d36b4c896e1 | 141 | //check for the start button (1) pressed, then released. |
knalty | 5:9d36b4c896e1 | 142 | |
knalty | 5:9d36b4c896e1 | 143 | if (TFC_PUSH_BUTTON_1_PRESSED) Start_PB_Pressed = 1; |
knalty | 5:9d36b4c896e1 | 144 | if ((!TFC_PUSH_BUTTON_1_PRESSED) & (Start_PB_Pressed)) // Falling edge detected |
knalty | 5:9d36b4c896e1 | 145 | { |
knalty | 5:9d36b4c896e1 | 146 | TFC_BAT_LED0_ON; // turn on back LED |
knalty | 5:9d36b4c896e1 | 147 | scratch = TFC_GetDIP_Switch(); // read DIP switches for initial speed |
knalty | 5:9d36b4c896e1 | 148 | DIP_Speed = 0; |
knalty | 5:9d36b4c896e1 | 149 | if (scratch & 1) DIP_Speed += 4; // SW1 |
knalty | 5:9d36b4c896e1 | 150 | if (scratch & 2) DIP_Speed += 2; // SW2 |
knalty | 5:9d36b4c896e1 | 151 | if (scratch & 4) DIP_Speed += 1; // SW3 |
knalty | 5:9d36b4c896e1 | 152 | Motor_Speed = 0.125*DIP_Speed; // scale 0..7 to 0.0 .. 0.875 |
knalty | 5:9d36b4c896e1 | 153 | |
knalty | 5:9d36b4c896e1 | 154 | Motor_ON = 1; // set flag used by run duration logic |
knalty | 5:9d36b4c896e1 | 155 | TFC_SetMotorPWM(Motor_Speed, Motor_Speed); // acts like Motor_Speed is zero |
knalty | 5:9d36b4c896e1 | 156 | TFC_HBRIDGE_ENABLE; // enable motors |
knalty | 5:9d36b4c896e1 | 157 | } |
knalty | 5:9d36b4c896e1 | 158 | |
knalty | 5:9d36b4c896e1 | 159 | // scan through the camera array, and find smallest value in the zone 32..96 |
knalty | 5:9d36b4c896e1 | 160 | |
knalty | 5:9d36b4c896e1 | 161 | if(Motor_ON) |
knalty | 5:9d36b4c896e1 | 162 | { |
knalty | 5:9d36b4c896e1 | 163 | Current_Min = TFC_LineScanImage0[32]; // TFC_LineScanImage0 |
knalty | 5:9d36b4c896e1 | 164 | Current_Location = 32; |
knalty | 5:9d36b4c896e1 | 165 | for (i=32;i<96;i++) |
knalty | 5:9d36b4c896e1 | 166 | { |
knalty | 5:9d36b4c896e1 | 167 | if(TFC_LineScanImage0[i] < Current_Min) |
knalty | 5:9d36b4c896e1 | 168 | { |
knalty | 5:9d36b4c896e1 | 169 | Current_Min = TFC_LineScanImage0[i]; |
knalty | 5:9d36b4c896e1 | 170 | Current_Location = i; |
knalty | 5:9d36b4c896e1 | 171 | } |
emh203 | 3:23cce037011f | 172 | } |
knalty | 5:9d36b4c896e1 | 173 | |
knalty | 5:9d36b4c896e1 | 174 | DarkSpot = (64.0 - Current_Location)*0.02; // gain will need to be played with. |
knalty | 5:9d36b4c896e1 | 175 | |
knalty | 5:9d36b4c896e1 | 176 | Servo_Position = DarkSpot + Servo_Offset + Camera_Offset; |
knalty | 5:9d36b4c896e1 | 177 | TFC_SetServo(0,Servo_Position); |
knalty | 5:9d36b4c896e1 | 178 | } |
knalty | 5:9d36b4c896e1 | 179 | |
emh203 | 3:23cce037011f | 180 | } |
emh203 | 3:23cce037011f | 181 | } |