-
Notifications
You must be signed in to change notification settings - Fork 0
/
marsbot.ino
310 lines (276 loc) · 8.49 KB
/
marsbot.ino
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
#include <Arduino.h>
#include "digitalWriteFast.h"
/**
* Hardware pin defines
*/
#define BOARD UKMARSBOT_V1
const int ENCODER_LEFT_CLK = 2;
const int ENCODER_RIGHT_CLK = 3;
const int ENCODER_LEFT_B = 4;
const int ENCODER_RIGHT_B = 5;
const int MOTOR_LEFT_DIR = 7;
const int MOTOR_RIGHT_DIR = 8;
const int MOTOR_LEFT_PWM = 9;
const int MOTOR_RIGHT_PWM = 10;
const int LED_RIGHT = 6;
const int LED_LEFT = 11;
const int EMITTER = 12;
const int SENSOR_0 = A0;
const int SENSOR_1 = A1;
const int SENSOR_2 = A2;
const int SENSOR_3 = A3;
const int SENSOR_4 = A4;
const int SENSOR_5 = A5;
const int FUNCTION_PIN = A6;
const int BATTERY_VOLTS = A7;
const float MAX_MOTOR_VOLTS = 6.0f;
/****/
// Global variables for sensor values and walls
// the default values for the front sensor when the robot is backed up to a wall
const int FRONT_REFERENCE = 44;
// the default values for the side sensors when the robot is centred in a cell
const int LEFT_REFERENCE = 38;
const int RIGHT_REFERENCE = 49;
// the values above which, a wall is seen
const int FRONT_WALL_THRESHOLD = FRONT_REFERENCE / 20; // minimum value to register a wall
const int LEFT_WALL_THRESHOLD = LEFT_REFERENCE / 2; // minimum value to register a wall
const int RIGHT_WALL_THRESHOLD = RIGHT_REFERENCE / 2; // minimum value to register a wall
// working copies of the reference values
int gFrontReference = FRONT_REFERENCE;
int gLeftReference = LEFT_REFERENCE;
int gRightReference = RIGHT_REFERENCE;
// the current value of the sensors
volatile int gSensorFront;
volatile int gSensorLeft;
volatile int gSensorRight;
// true f a wall is present
volatile bool gFrontWall;
volatile bool gLeftWall;
volatile bool gRightWall;
// steering and turn position errors
volatile int gSensorFrontError; // zero when robot in cell centre
volatile float gSensorCTE; // zero when robot in cell centre
volatile int32_t encoderLeftCount;
volatile int32_t encoderRightCount;
// Timing variables
uint32_t updateTime;
uint32_t updateInterval = 40; // (ms)
const float batteryDividerRatio = 2.0f;
float gBatteryVolts;
float getBatteryVolts() {
int adcValue = analogRead(BATTERY_VOLTS);
gBatteryVolts = adcValue * (5.0f * batteryDividerRatio / 1023.0f);
return gBatteryVolts;
}
void setupEncoder() {
// left
pinMode(ENCODER_LEFT_CLK, INPUT);
pinMode(ENCODER_LEFT_B, INPUT);
// configure the pin change
bitClear(EICRA, ISC01);
bitSet(EICRA, ISC00);
// enable the interrupt
bitSet(EIMSK, INT0);
encoderLeftCount = 0;
// right
pinMode(ENCODER_RIGHT_CLK, INPUT);
pinMode(ENCODER_RIGHT_B, INPUT);
// configure the pin change
bitClear(EICRA, ISC11);
bitSet(EICRA, ISC10);
// enable the interrupt
bitSet(EIMSK, INT1);
encoderRightCount = 0;
}
void analogueSetup() {
// increase speed of ADC conversions to 28us each
// by changing the clock prescaler from 128 to 16
bitClear(ADCSRA, ADPS0);
bitClear(ADCSRA, ADPS1);
bitSet(ADCSRA, ADPS2);
}
ISR(INT0_vect) {
static bool oldB = 0;
bool newB = bool(digitalReadFast(ENCODER_LEFT_B));
bool newA = bool(digitalReadFast(ENCODER_LEFT_CLK)) ^ newB;
if (newA == oldB) {
encoderLeftCount--;
} else {
encoderLeftCount++;
}
oldB = newB;
}
ISR(INT1_vect) {
static bool oldB = 0;
bool newB = bool(digitalReadFast(ENCODER_RIGHT_B));
bool newA = bool(digitalReadFast(ENCODER_RIGHT_CLK)) ^ newB;
if (newA == oldB) {
encoderRightCount++;
} else {
encoderRightCount--;
}
oldB = newB;
}
// Timer interrupt for sensor updates
ISR(TIMER2_COMPA_vect) {
updateWallSensor();
}
void updateWallSensor() {
// first read them dark
int right = analogRead(A0);
int front = analogRead(A1);
int left = analogRead(A2);
// light them up
digitalWrite(EMITTER, 1);
// wait until all the detectors are stable
delayMicroseconds(50);
// now find the differences
right = analogRead(A0) - right;
front = analogRead(A1) - front;
left = analogRead(A2) - left;
// and go dark again.
digitalWrite(EMITTER, 0);
gFrontWall = front > gFrontReference / 4;
gLeftWall = left > gLeftReference / 2;
gRightWall = right > gRightReference / 2;
digitalWrite(LED_LEFT, gLeftWall);
digitalWrite(LED_RIGHT, gRightWall);
digitalWrite(LED_BUILTIN, gFrontWall);
// digitalWrite(LED_LEFT, gFrontWall);
// digitalWrite(LED_RIGHT, gFrontWall);
// calculate the alignment error - too far right is negative
if ((left + right) > (gLeftReference + gRightReference) / 4) {
if (left > right) {
gSensorCTE = (left - LEFT_REFERENCE);
gSensorCTE /= left;
} else {
gSensorCTE = (RIGHT_REFERENCE - right);
gSensorCTE /= right;
}
} else {
gSensorCTE = 0;
}
// make the results available to the rest of the program
gSensorLeft= left;
gSensorRight = right;
gSensorFront = front;
}
void setupSystick() {
bitClear(TCCR2A, WGM20);
bitSet(TCCR2A, WGM21);
bitClear(TCCR2B, WGM22);
bitSet(TCCR2B, CS22);
bitClear(TCCR2B, CS21);
bitSet(TCCR2B, CS20);
OCR2A = 249;
bitSet(TIMSK2, OCIE2A);
}
void motorSetup() {
pinMode(MOTOR_LEFT_DIR, OUTPUT);
pinMode(MOTOR_RIGHT_DIR, OUTPUT);
pinMode(MOTOR_LEFT_PWM, OUTPUT);
pinMode(MOTOR_RIGHT_PWM, OUTPUT);
digitalWrite(MOTOR_LEFT_PWM, 0);
digitalWrite(MOTOR_LEFT_DIR, 0);
digitalWrite(MOTOR_RIGHT_PWM, 0);
digitalWrite(MOTOR_RIGHT_DIR, 0);
}
void setLeftMotorPWM(int pwm) {
pwm = constrain(pwm, -255, 255);
if (pwm < 0) {
digitalWrite(MOTOR_LEFT_DIR, 0);
analogWrite(MOTOR_LEFT_PWM, -pwm);
} else {
digitalWrite(MOTOR_LEFT_DIR, 1);
analogWrite(MOTOR_LEFT_PWM, pwm);
}
}
void setRightMotorPWM(int pwm) {
pwm = constrain(pwm, -255, 255);
if (pwm < 0) {
digitalWrite(MOTOR_RIGHT_DIR, 0);
analogWrite(MOTOR_RIGHT_PWM, -pwm);
} else {
digitalWrite(MOTOR_RIGHT_DIR, 1);
analogWrite(MOTOR_RIGHT_PWM, pwm);
}
}
void setMotorPWM(int left, int right) {
setLeftMotorPWM(left);
setRightMotorPWM(right);
}
void setLeftMotorVolts(float volts) {
volts = constrain(volts, -MAX_MOTOR_VOLTS, MAX_MOTOR_VOLTS);
int motorPWM = (int)((255.0f * volts) / gBatteryVolts);
setLeftMotorPWM(motorPWM);
}
void setRightMotorVolts(float volts) {
volts = constrain(volts, -MAX_MOTOR_VOLTS, MAX_MOTOR_VOLTS);
int motorPWM = (int)((255.0f * volts) / gBatteryVolts);
setRightMotorPWM(motorPWM);
}
void setMotorVolts(float left, float right) {
setLeftMotorVolts(left);
setRightMotorVolts(right);
}
void setup() {
Serial.begin(9600);
digitalWrite(EMITTER, 0); // Turn off emitter initially
pinMode(EMITTER, OUTPUT);
pinMode(LED_RIGHT, OUTPUT);
pinMode(LED_LEFT, OUTPUT);
setupEncoder();
motorSetup();
analogueSetup(); // increase the ADC conversion speed
setupSystick();
updateTime = millis() + updateInterval;
}
void loop() {
if (millis() > updateTime) {
updateTime += updateInterval;
// int adcValue = analogRead(BATTERY_VOLTS);
getBatteryVolts();
// Convert the three boolean values into a single integer value (binary representation)
int inputValue = (gFrontWall << 2) | (gLeftWall << 1) | gRightWall;
switch (inputValue) {
case 0: // input1 = 0, input2 = 0, input3 = 0
setMotorVolts(2, 2); // go forward
break;
case 1: // input1 = 0, input2 = 0, input3 = 1
setMotorVolts(-2, 2); // turn left
break;
case 2: // input1 = 0, input2 = 1, input3 = 0
setMotorVolts(2, -2); //turn right
break;
case 3: // input1 = 0, input2 = 1, input3 = 1
setMotorVolts(2, 2); // go forward
break;
case 4: // input1 = 1, input2 = 0, input3 = 0
setMotorVolts(-2, 2); // turn left
break;
case 5: // input1 = 1, input2 = 0, input3 = 1
setMotorVolts(-2, 2); // turn left
break;
case 6: // input1 = 1, input2 = 1, input3 = 0
setMotorVolts(2, -2); //turn right
break;
case 7: // input1 = 1, input2 = 1, input3 = 1
setMotorVolts(1, -4); //turn around
break;
default:
// Serial.println("Invalid input combination.");
setMotorVolts(0, 0); // stop
break;
}
// Debugging information
Serial.print("Right: ");
Serial.print(gSensorRight);
Serial.print(" Front: ");
Serial.print(gSensorFront);
Serial.print(" Left: ");
Serial.print(gSensorLeft);
Serial.print(" Error: ");
Serial.print(gSensorCTE);
Serial.println();
}
}