Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
#include "pitches.h"
/*
  Code for driving remote controlled tank
 Includes code for:
 external interrupt 0 on pin 2
 midi sounds through speaker using tone() on pin 8
 H-bridge for driving motors
 Flashing LED that doesn't use a delay
 Serial port communication
 */

//Number of melodies to allocate for the speaker
#define NUM_SONGS 3

//Phase Definitions
#define STOPPED 0
#define FORWARD 1
#define RIGHT 2
#define LEFT 3
#define REVERSE 4

//H-Bridge Pin assignments
const unsigned char PIN_HBRIDGE_1A = 5;
const unsigned char PIN_HBRIDGE_2A = 3;
const unsigned char PIN_HBRIDGE_3A = 6;
const unsigned char PIN_HBRIDGE_4A = 9;

const unsigned char ledPin = 13; // LED that will flash

const unsigned char speakerPin = 8; // Speaker for melodies

const unsigned char buttonPin = 2; // the number of the pushbutton pin
const unsigned char int0 = 0; // pin 2 is attached to interrupt 0

//LED settings
long ledInterval = 500; // interval at which to blink (milliseconds)
int ledState = LOW;  // start LED turned off
long ledPreviousMillis = 0; // keep track of the last flash of the LED

//Serial port settings
unsigned char prompt = 1;  // should we prompt for a keystroke?
int inByte = 0;         // incoming serial byte

//Determines the tanks current task
unsigned int phase = STOPPED;

//Melody containers
int melodyLength[NUM_SONGS];
int* melody[NUM_SONGS];
int* noteDurations[NUM_SONGS];

//Melody 0
int melodyLength0 = 8;
int melody0[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
int noteDurations0[] = {
  4, 8, 8, 4,4,4,4,4 };

//Melody 1 - Beep
int melodyLength1 = 1;
int melody1[] = {
  NOTE_C4};
int noteDurations1[] = {
  2};

//Melody 2 - Lord of the Rings theme
int melodyLength2 = 16;
int melody2[] = {
  NOTE_A4,NOTE_G4,NOTE_G4,NOTE_G4,NOTE_A4,
  NOTE_D5,NOTE_E5,NOTE_F5,NOTE_E5,NOTE_D5,NOTE_C5,NOTE_D5,NOTE_E5,
  NOTE_D5,NOTE_C5,NOTE_B4};
int noteDurations2[] = {
  1,1,8,8,1,8,8,1,8,8,1,8,8,1,2,2};


void setup() {
  //Attach pins
  pinMode(PIN_HBRIDGE_1A, OUTPUT);
  pinMode(PIN_HBRIDGE_2A, OUTPUT);
  pinMode(PIN_HBRIDGE_3A, OUTPUT);
  pinMode(PIN_HBRIDGE_4A, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);

  //Setup interrupts
  attachInterrupt(int0, ButtonInterrupt, RISING);

  // start serial port at 9600 bps:
  Serial.begin(9600);

  //Setup melodies and play startup sound
  CreateMelodies();
  PlayMelody(0);

  Serial.println("Starting tank...");
}

//Interrupt handler for button press
void ButtonInterrupt() {
  //Debounce button press
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  // If interrupts come faster than 200ms, assume it's a bounce and ignore
  if(interruptTime - lastInterruptTime > 200) {
    //Button interrupt handler
    //Increment phase, rollover after 4
    Serial.println("Interrupt!!");
    if (++phase == 5)
      phase = STOPPED;
  }
  lastInterruptTime = interruptTime;
}

void loop() {
  if (prompt) {
    PromptKeyPress();
  }

  if (Serial.available() > 0) {
    ReadKeyPress();
  }

  //This block of code can be uncommented and adjusted
  //for atonomous dead reckoning of the tank
  /*
  TankForward();
   delay(4000);
   TankRight();
   delay(1500);
   TankForward();
   delay(4000);
   TankLeft();
   delay(1500);
   TankStop();
   delay(2000);
   */

  switch(phase) {
  case STOPPED:
    TankStop();
    Serial.println("Tank stop");
    break;
  case FORWARD:
    TankForward();
    Serial.println("Tank forward");
    break;
  case RIGHT:
    TankRight();
    Serial.println("Tank right");
    break;
  case LEFT:
    TankLeft();
    Serial.println("Tank left");
    break;
  case REVERSE:
    TankReverse();
    Serial.println("Tank reverse");
    break;
  default:
    TankStop();
    Serial.println("Tank stop");
    break;
  }

  FlashLed();
  //  PlayMelody(1);
}

//Sets up melodies
void CreateMelodies() {
  Serial.println("Creating melodies...");
  melodyLength[0] = melodyLength0;
  melody[0] = melody0;
  noteDurations[0] = noteDurations0;

  melodyLength[1] = melodyLength1;
  melody[1] = melody1;
  noteDurations[1] = noteDurations1;

  melodyLength[2] = melodyLength2;
  melody[2] = melody2;
  noteDurations[2] = noteDurations2;
  Serial.println("Done.");
}

//Plays melodies by assigned number
void PlayMelody(int s) {
  Serial.println("Playing melody...");
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < melodyLength[s]; thisNote++) {

    // to calculate the note duration, take one second 
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[s][thisNote];
    tone(speakerPin, melody[s][thisNote],noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
  }
  Serial.println("Done.");
}

void PromptKeyPress() {
  Serial.println("Press a number");
  prompt = 0; 
}

//Read key presses over serial
void ReadKeyPress() {
  inByte = Serial.read();
  switch (inByte)
  {
  case '2':
    phase = REVERSE;
    break;
  case '4':
    phase = LEFT;
    break;
  case '5':
    phase = STOPPED;
    break;
  case '6':
    phase = RIGHT;
    break;
  case '8':
    phase = FORWARD;
    break;
  default:
    Serial.println("Invalid command");
    break;
  }
  prompt = 1;
}

//Flashes onboard LED periodically without using DELAY
void FlashLed() {
  if (millis() - ledPreviousMillis > ledInterval) {
    // save the last time you blinked the LED 
    ledPreviousMillis = millis();   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}


//These functions control the tank
void TankForward() {
  MotorLeftForward();
  MotorRightForward();
}

void TankStop() {
  MotorLeftStop();
  MotorRightStop(); 
}

void TankReverse() {
  MotorLeftReverse();
  MotorRightReverse();
}

void TankLeft() {
  MotorLeftForward();
  MotorRightReverse();
}

void TankRight() {
  MotorLeftReverse();
  MotorRightForward();
}

//These functions perform the low-level control of H-Bridge
void MotorRightStop() {
  digitalWrite(PIN_HBRIDGE_1A, LOW);
  digitalWrite(PIN_HBRIDGE_2A, LOW);
}

void MotorRightForward() {
  digitalWrite(PIN_HBRIDGE_1A, HIGH);
  digitalWrite(PIN_HBRIDGE_2A, LOW);
}

void MotorRightReverse() {
  digitalWrite(PIN_HBRIDGE_1A, LOW);
  digitalWrite(PIN_HBRIDGE_2A, HIGH);
}

void MotorLeftStop() {
  digitalWrite(PIN_HBRIDGE_3A, LOW);
  digitalWrite(PIN_HBRIDGE_4A, LOW);
}

void MotorLeftForward() {
  digitalWrite(PIN_HBRIDGE_3A, LOW);
  digitalWrite(PIN_HBRIDGE_4A, HIGH);
}

void MotorLeftReverse() {
  digitalWrite(PIN_HBRIDGE_3A, HIGH);
  digitalWrite(PIN_HBRIDGE_4A, LOW);
}