This is an example program that actually allows the car to race using the FRDM-TFC library!

Dependencies:   FRDM-TFC

Overview

This program is an example program that uses the FRDM-TFC library to actually permit a car using the FDRM-TFC shield + FRDM-KL25Z to race around a center line track.

Car Hookup

Motors

  • Code written assuming left motor hooked to B1(red)/B2(black) and right motor hooked to A1(red)/A2(black).

Battery

  • Be sure to hook positive (red) to 'Vbat' and negative (black) to 'Gnd'

Steering Servo

  • Servo must be hooked up with black wire innermost (away from LEDs).
  • Also be sure to mount servo on chassis with wire coming out the right side of the car.

Camera

  • Camera must be hooked up with black wire towards LEDs on the shield board.
  • Be sure to mount camera on tower with connector down towards the bottom.

Potentiometers (Pots)

  • Pots by default should have arrows pointing toward battery/motor hookup (for demo mods default).

Car Hardware Controls

DIP SWITCH CONTROLS:

  • Switch 1: Controls whether running main racing program (ON) or Demo program (OFF). Function of other 3 switches depend on this first switch.

RACING MODE (Switch 1 = ON)

  • Switch 2: Logging frame camera data to RAM while racing. Enable (ON) or Disable (OFF).
  • Switch 3: Risky / faster racing (ON); Conservative / slower race option (OFF). NOTE: Faster mode may cause car to fall off track. Needs tweaking...
  • Switch 4: Enable Start Gate Stop (ON) or Disable (OFF). NOTE: May not actually stop at start gate. Needs tweaking...
  • POTs 1,2 - controls nothing at the moment
  • PUSHBUTTON A - START car race!
  • PUSHBUTTON B - END CAR RACE / (while holding down when 'log frame data' active will also output terminal data gathered during race)
  • LEDs 1,2 light when Track is found
  • LEDs 0,3 light when Start Gate is Found

DEMO MODE 0 (Switch 1 = OFF; Switch 2 = OFF, Switch 3 = OFF)

  • PUSHBUTTON A - Light LED 0
  • PUSHBUTTON B - Light LED 3

DEMO MODE 1 (Switch 1 = OFF; Switch 2 = ON, Switch 3 = OFF)

  • POT 1 - Controls Servo: CCW = left; CW = right

DEMO MODE 2 (Switch 1 = OFF; Switch 2 = OFF, Switch 3 = ON)

  • POT 1 - Controls speed of right wheel: CCW = reverse; CW = forward
  • POT 2 - Controls speed of left wheel: CCW = reverse; CW = forward
  • NOTE In this mode the high pitched whine heard is of the H-bridge being active. To disable whine, briefly put into demo mode 1 above.

DEMO MODE 3 (Switch 1 = OFF; Switch 2 = ON, Switch 3 = ON)

  • Outputs camera data captured to terminal in CSV format, once every second.

Car Calibration

Serial Terminal

  • Download your favorite Terminal application (I use TeraTerm. Set it for 115200 baud, 8bit, none, 1bit.
  • But first you have to be sure that Windows mbed serial driver has been installed: Windows serial config.

Camera

  • If you want to hook up a scope, here are the pins of the camera interface from left to right: ground, 3.3V, SI, CLK, Analog_Out.
  • You want to hook up channel 1 between Analog_Out and Ground, channel 2 between SI and ground. SI can serve as your trigger.
  • Alternatively if you only want to use one channel, you can only hook up to Analog_Out and use triggering on the same channel.
  • Be sure to focus the camera properly. See demo video.
  • Be sure to prevent light noise on camera: Avoid Light Noise
  • More camera info

Servo/Steering

  • You will need to put the car into demo mode 1 and connect up a terminal to the serial port in order to get feedback on the values for your particular servo as hooked up. Then change MAX_STEER_LEFT and MAX_STEER_RIGHT in Spices.cpp with these values to tell the program how your servo is hooked up.
  • Here's a video where values are output to LCD to make it easier: http://youtu.be/fp5gyfEMf50

Speed Control

  • This program does not have proper speed control but does modify the speed slightly based on recent error results from the camera. It also modifies the differential speed to each wheel to have better control around curves.
  • While debugging your car you may want to lower the speed. See the function SpeedControl in Spices.cpp. There you can change which speed method you'd like to use. Currently is using value of 1, which gets maximum speed from TUNE_SPEED constant. Reduce to 0.4 or 0.5 when debugging car around the car (mainly to minimize crash forces!).

Strange Gotchas

Glitchy Motors

  • Apparently there is contention between TPM0_CH0 and OpenSDA micro that causes strange issues with Motors (PWM interference). This will cause glitches in motor activty when hooked up to USB only: Found contention

More Info

Committer:
redxeth
Date:
Sun Apr 20 03:33:03 2014 +0000
Revision:
0:98e98e01a6ce
Initial version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
redxeth 0:98e98e01a6ce 1 #include "mbed.h"
redxeth 0:98e98e01a6ce 2 #include "TFC.h"
redxeth 0:98e98e01a6ce 3
redxeth 0:98e98e01a6ce 4 #include "common.h"
redxeth 0:98e98e01a6ce 5 #include "Spices.h"
redxeth 0:98e98e01a6ce 6
redxeth 0:98e98e01a6ce 7
redxeth 0:98e98e01a6ce 8 void TFC_TickerUpdate()
redxeth 0:98e98e01a6ce 9 {
redxeth 0:98e98e01a6ce 10 int i;
redxeth 0:98e98e01a6ce 11
redxeth 0:98e98e01a6ce 12 for(i=0; i<NUM_TFC_TICKERS; i++)
redxeth 0:98e98e01a6ce 13 {
redxeth 0:98e98e01a6ce 14 if(TFC_Ticker[i]<0xFFFFFFFF)
redxeth 0:98e98e01a6ce 15 {
redxeth 0:98e98e01a6ce 16 TFC_Ticker[i]++;
redxeth 0:98e98e01a6ce 17 }
redxeth 0:98e98e01a6ce 18 }
redxeth 0:98e98e01a6ce 19 }
redxeth 0:98e98e01a6ce 20
redxeth 0:98e98e01a6ce 21 void DemoProgram()
redxeth 0:98e98e01a6ce 22 {
redxeth 0:98e98e01a6ce 23 uint32_t i,j,t = 0;
redxeth 0:98e98e01a6ce 24 float ReadPot0, ReadPot1;
redxeth 0:98e98e01a6ce 25
redxeth 0:98e98e01a6ce 26
redxeth 0:98e98e01a6ce 27 //This Demo program will look at the middle 2 switch to select one of 4 demo modes.
redxeth 0:98e98e01a6ce 28 //Let's look at the middle 2 switches
redxeth 0:98e98e01a6ce 29 switch((TFC_GetDIP_Switch()>>1)&0x03)
redxeth 0:98e98e01a6ce 30 {
redxeth 0:98e98e01a6ce 31 default:
redxeth 0:98e98e01a6ce 32 case 0 :
redxeth 0:98e98e01a6ce 33 //Demo mode 0 just tests the switches and LED's
redxeth 0:98e98e01a6ce 34 if(TFC_PUSH_BUTTON_0_PRESSED)
redxeth 0:98e98e01a6ce 35 TFC_BAT_LED0_ON;
redxeth 0:98e98e01a6ce 36 else
redxeth 0:98e98e01a6ce 37 TFC_BAT_LED0_OFF;
redxeth 0:98e98e01a6ce 38
redxeth 0:98e98e01a6ce 39 if(TFC_PUSH_BUTTON_1_PRESSED)
redxeth 0:98e98e01a6ce 40 TFC_BAT_LED3_ON;
redxeth 0:98e98e01a6ce 41 else
redxeth 0:98e98e01a6ce 42 TFC_BAT_LED3_OFF;
redxeth 0:98e98e01a6ce 43
redxeth 0:98e98e01a6ce 44
redxeth 0:98e98e01a6ce 45 /* if(TFC_GetDIP_Switch()&0x01)
redxeth 0:98e98e01a6ce 46 TFC_BAT_LED1_ON;
redxeth 0:98e98e01a6ce 47 else
redxeth 0:98e98e01a6ce 48 TFC_BAT_LED1_OFF;
redxeth 0:98e98e01a6ce 49
redxeth 0:98e98e01a6ce 50 if(TFC_GetDIP_Switch()&0x08)
redxeth 0:98e98e01a6ce 51 TFC_BAT_LED2_ON;
redxeth 0:98e98e01a6ce 52 else
redxeth 0:98e98e01a6ce 53 TFC_BAT_LED2_OFF; */
redxeth 0:98e98e01a6ce 54
redxeth 0:98e98e01a6ce 55 break;
redxeth 0:98e98e01a6ce 56
redxeth 0:98e98e01a6ce 57 case 1:
redxeth 0:98e98e01a6ce 58 TFC_HBRIDGE_DISABLE;
redxeth 0:98e98e01a6ce 59
redxeth 0:98e98e01a6ce 60 // if (TFC_HBRIDGE_ENABLED) {
redxeth 0:98e98e01a6ce 61
redxeth 0:98e98e01a6ce 62 // TFC_HBRIDGE_ENABLED = false;
redxeth 0:98e98e01a6ce 63 // }
redxeth 0:98e98e01a6ce 64
redxeth 0:98e98e01a6ce 65 //Demo mode 1 will just move the servos with the on-board potentiometers
redxeth 0:98e98e01a6ce 66 if(TFC_Ticker[0]>=20) // every 40mS...
redxeth 0:98e98e01a6ce 67 {
redxeth 0:98e98e01a6ce 68 TFC_Ticker[0] = 0; //reset the Ticker
redxeth 0:98e98e01a6ce 69 //update the Servos
redxeth 0:98e98e01a6ce 70 ReadPot0 = TFC_ReadPot(0);
redxeth 0:98e98e01a6ce 71 ReadPot1 = TFC_ReadPot(1);
redxeth 0:98e98e01a6ce 72 TFC_SetServo(0,ReadPot0);
redxeth 0:98e98e01a6ce 73 TFC_SetServo(1,ReadPot1);
redxeth 0:98e98e01a6ce 74 TERMINAL_PRINTF("Pot0 = %1.2f\r\n", ReadPot0);
redxeth 0:98e98e01a6ce 75 // TERMINAL_PRINTF("Pot1 = %1.2f\r\n", ReadPot1);
redxeth 0:98e98e01a6ce 76 }
redxeth 0:98e98e01a6ce 77 //Let's put a pattern on the LEDs
redxeth 0:98e98e01a6ce 78 if(TFC_Ticker[1] >= 125) // every 250mS... cycle through LEDs
redxeth 0:98e98e01a6ce 79 {
redxeth 0:98e98e01a6ce 80 TFC_Ticker[1] = 0;
redxeth 0:98e98e01a6ce 81 t++;
redxeth 0:98e98e01a6ce 82 if(t>4)
redxeth 0:98e98e01a6ce 83 {
redxeth 0:98e98e01a6ce 84 t=0;
redxeth 0:98e98e01a6ce 85 }
redxeth 0:98e98e01a6ce 86 TFC_SetBatteryLED_Level(t);
redxeth 0:98e98e01a6ce 87 }
redxeth 0:98e98e01a6ce 88
redxeth 0:98e98e01a6ce 89 TFC_SetMotorPWM(0,0); //Make sure motors are off
redxeth 0:98e98e01a6ce 90 TFC_HBRIDGE_DISABLE;
redxeth 0:98e98e01a6ce 91
redxeth 0:98e98e01a6ce 92 break;
redxeth 0:98e98e01a6ce 93
redxeth 0:98e98e01a6ce 94 case 2 :
redxeth 0:98e98e01a6ce 95 TFC_HBRIDGE_ENABLE;
redxeth 0:98e98e01a6ce 96
redxeth 0:98e98e01a6ce 97 ReadPot0 = TFC_ReadPot(0);
redxeth 0:98e98e01a6ce 98 ReadPot1 = TFC_ReadPot(1);
redxeth 0:98e98e01a6ce 99 // TERMINAL_PRINTF("Pot0 = %1.2f\n", ReadPot0);
redxeth 0:98e98e01a6ce 100 // TERMINAL_PRINTF("Pot1 = %1.2f\n", ReadPot1);
redxeth 0:98e98e01a6ce 101 TFC_SetMotorPWM(ReadPot0,ReadPot1);
redxeth 0:98e98e01a6ce 102
redxeth 0:98e98e01a6ce 103 //Let's put a pattern on the LEDs
redxeth 0:98e98e01a6ce 104 if(TFC_Ticker[1] >= 125)
redxeth 0:98e98e01a6ce 105 {
redxeth 0:98e98e01a6ce 106 TFC_Ticker[1] = 0;
redxeth 0:98e98e01a6ce 107 t++;
redxeth 0:98e98e01a6ce 108 if(t>4)
redxeth 0:98e98e01a6ce 109 {
redxeth 0:98e98e01a6ce 110 t=0;
redxeth 0:98e98e01a6ce 111 }
redxeth 0:98e98e01a6ce 112 TFC_SetBatteryLED_Level(t);
redxeth 0:98e98e01a6ce 113 }
redxeth 0:98e98e01a6ce 114 break;
redxeth 0:98e98e01a6ce 115
redxeth 0:98e98e01a6ce 116 case 3 :
redxeth 0:98e98e01a6ce 117 //Demo Mode 3 will be in Freescale Garage Mode. It will beam data from the Camera to the
redxeth 0:98e98e01a6ce 118 //Labview Application
redxeth 0:98e98e01a6ce 119 //note that there are some issues
redxeth 0:98e98e01a6ce 120 if(TFC_Ticker[0]>1000 && TFC_LineScanImageReady>0) // every 2s ...
redxeth 0:98e98e01a6ce 121 {
redxeth 0:98e98e01a6ce 122 TFC_Ticker[0] = 0;
redxeth 0:98e98e01a6ce 123 TFC_LineScanImageReady=0; // must reset to 0 after detecting non-zero
redxeth 0:98e98e01a6ce 124
redxeth 0:98e98e01a6ce 125 if(t==0)
redxeth 0:98e98e01a6ce 126 t=4;
redxeth 0:98e98e01a6ce 127 else
redxeth 0:98e98e01a6ce 128 t--;
redxeth 0:98e98e01a6ce 129
redxeth 0:98e98e01a6ce 130 TFC_SetBatteryLED_Level(t);
redxeth 0:98e98e01a6ce 131
redxeth 0:98e98e01a6ce 132 for(i=0;i<8;i++) // print one line worth of data (128) from Camera 0
redxeth 0:98e98e01a6ce 133 {
redxeth 0:98e98e01a6ce 134 for(j=0;j<16;j++)
redxeth 0:98e98e01a6ce 135 {
redxeth 0:98e98e01a6ce 136
redxeth 0:98e98e01a6ce 137 TERMINAL_PRINTF("0x%X",TFC_LineScanImage0[(i*16)+j]);
redxeth 0:98e98e01a6ce 138
redxeth 0:98e98e01a6ce 139 if((i==7) && (j==15)) // when last data reached put in line return
redxeth 0:98e98e01a6ce 140 TERMINAL_PRINTF("\r\n",TFC_LineScanImage0[(i*16)+j]);
redxeth 0:98e98e01a6ce 141 else
redxeth 0:98e98e01a6ce 142 TERMINAL_PRINTF(",",TFC_LineScanImage0[(i*16)+j]);
redxeth 0:98e98e01a6ce 143
redxeth 0:98e98e01a6ce 144 }
redxeth 0:98e98e01a6ce 145 wait_ms(10);
redxeth 0:98e98e01a6ce 146 }
redxeth 0:98e98e01a6ce 147
redxeth 0:98e98e01a6ce 148 /* for(i=0;i<8;i++) // print one line worth of data (128) from Camera 1 ??
redxeth 0:98e98e01a6ce 149 {
redxeth 0:98e98e01a6ce 150 for(j=0;j<16;j++)
redxeth 0:98e98e01a6ce 151 {
redxeth 0:98e98e01a6ce 152 TERMINAL_PRINTF("0x%X",TFC_LineScanImage1[(i*16)+j]);
redxeth 0:98e98e01a6ce 153
redxeth 0:98e98e01a6ce 154 if((i==7) && (j==15)) // when last data reached put in line return
redxeth 0:98e98e01a6ce 155 TERMINAL_PRINTF("\r\n",TFC_LineScanImage1[(i*16)+j]);
redxeth 0:98e98e01a6ce 156 else
redxeth 0:98e98e01a6ce 157 TERMINAL_PRINTF(",",TFC_LineScanImage1[(i*16)+j]);
redxeth 0:98e98e01a6ce 158 }
redxeth 0:98e98e01a6ce 159
redxeth 0:98e98e01a6ce 160 wait_ms(10);
redxeth 0:98e98e01a6ce 161 } */
redxeth 0:98e98e01a6ce 162
redxeth 0:98e98e01a6ce 163 }
redxeth 0:98e98e01a6ce 164
redxeth 0:98e98e01a6ce 165
redxeth 0:98e98e01a6ce 166
redxeth 0:98e98e01a6ce 167 break;
redxeth 0:98e98e01a6ce 168 } // end case
redxeth 0:98e98e01a6ce 169
redxeth 0:98e98e01a6ce 170 }
redxeth 0:98e98e01a6ce 171
redxeth 0:98e98e01a6ce 172
redxeth 0:98e98e01a6ce 173 int main()
redxeth 0:98e98e01a6ce 174 {
redxeth 0:98e98e01a6ce 175 // TERMINAL TYPE
redxeth 0:98e98e01a6ce 176 PC.baud(115200); // works with Excel and TeraTerm
redxeth 0:98e98e01a6ce 177 //PC.baud(9600); // works with USB Serial Monitor Lite: https://play.google.com/store/apps/details?id=jp.ksksue.app.terminal; doesn't work > 9600
redxeth 0:98e98e01a6ce 178 TFC_TickerObj.attach_us(&TFC_TickerUpdate,2000); // update ticker array every 2mS (2000 uS)
redxeth 0:98e98e01a6ce 179
redxeth 0:98e98e01a6ce 180 TFC_Init();
redxeth 0:98e98e01a6ce 181
redxeth 0:98e98e01a6ce 182 for(;;)
redxeth 0:98e98e01a6ce 183 {
redxeth 0:98e98e01a6ce 184 //TFC_Task must be called in your main loop. This keeps certain processing happy (I.E. Serial port queue check)
redxeth 0:98e98e01a6ce 185 // TFC_Task();
redxeth 0:98e98e01a6ce 186
redxeth 0:98e98e01a6ce 187
redxeth 0:98e98e01a6ce 188 // If DIP switch 1 is high, then run MCP, else Demo program
redxeth 0:98e98e01a6ce 189 if(TFC_GetDIP_Switch()&0x01)
redxeth 0:98e98e01a6ce 190 // Run MCP
redxeth 0:98e98e01a6ce 191 MasterControlProgram();
redxeth 0:98e98e01a6ce 192 else
redxeth 0:98e98e01a6ce 193 // Run Demo Program
redxeth 0:98e98e01a6ce 194 DemoProgram();
redxeth 0:98e98e01a6ce 195
redxeth 0:98e98e01a6ce 196 } // end of infinite for loop
redxeth 0:98e98e01a6ce 197
redxeth 0:98e98e01a6ce 198
redxeth 0:98e98e01a6ce 199 }
redxeth 0:98e98e01a6ce 200