This is the actual emulator, running the actual Blink program. Nothing here is a recording.
const int IN1 = 2, IN2 = 3, IN3 = 4, IN4 = 5, ENA = 9, ENB = 10;
const int EYE_L = 7, EYE_R = 8;
const int FAST = 200, SLOW = 70;
// Which eye saw the line last. A robot that has lost the line entirely knows nothing about
// where it went EXCEPT this, and it is enough: the line left on the side that saw it last.
int lastSeen = 0;
void wheels(int left, int right) {
digitalWrite(IN1, left > 0 ? HIGH : LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, right > 0 ? HIGH : LOW);
digitalWrite(IN4, LOW);
analogWrite(ENA, left);
analogWrite(ENB, right);
}
void setup() {
int outs[] = {IN1, IN2, IN3, IN4, ENA, ENB};
for (int i = 0; i < 6; i++) pinMode(outs[i], OUTPUT);
pinMode(EYE_L, INPUT);
pinMode(EYE_R, INPUT);
}
void loop() {
bool leftOnLine = digitalRead(EYE_L) == LOW;
bool rightOnLine = digitalRead(EYE_R) == LOW;
if (leftOnLine && !rightOnLine) {
lastSeen = -1;
wheels(SLOW, FAST);
} else if (rightOnLine && !leftOnLine) {
lastSeen = 1;
wheels(FAST, SLOW);
} else if (leftOnLine && rightOnLine) {
wheels(FAST, FAST);
} else {
// Both eyes off the line. Driving straight on here is what loses a robot for good on a
// sharp corner: it carries on into open floor and never sees the line again. Turn back
// towards whichever eye saw it last and it sweeps until the line comes round again.
if (lastSeen < 0) wheels(0, FAST);
else if (lastSeen > 0) wheels(FAST, 0);
else wheels(FAST, FAST);
}
delay(5);
}void loop() {
int l = ping(TRIG_L, ECHO_L);
int f = ping(TRIG_F, ECHO_F);
int r = ping(TRIG_R, ECHO_R);
// The rule. Four questions, and THE ORDER IS THE ALGORITHM - swap any two lines and you have
// built a different robot.
if (l > SIDE_OPEN_CM) {
spinLeft(QUARTER_MS); // a gap on the left is always taken. Always.
} else if (f > FRONT_OPEN_CM) {
// straight on: nothing to do but drive
} else if (r > SIDE_OPEN_CM) {
spinRight(QUARTER_MS); // left is wall, ahead is wall: the only way on is right
} else {
spinLeft(QUARTER_MS * 2); // dead end. All the way round, and the hand goes back on
} // the same wall it was already holding.
advanceCell();
}