#include <Stepper.h>
#define GLOBAL_DELAY 50
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Connect a stepper motor with 200 steps per revolution (1.8 degree) to motor port #2 (M3 and M4)
Adafruit_StepperMotor *rotor = AFMS.getStepper(200, 1);
Adafruit_StepperMotor *piston = AFMS.getStepper(200, 2);
///////////////////////////////////////
// CONSTANTS
namespace State {
// These Values should be freely changeable, so long as no two values are equal
enum Value {
Unknown = -1,
Empty = 0,
Block1 = 1,
Block2 = 2,
Block3 = 3,
};
}
const int BLOCK_COUNT = 3; //< The number of slot positions
const int DELAY = 150;
const int SENSOR_DELAY = 100;
const int sensor1 = 13;
const int sensor2 = 12;
const int SORT_123[] = {
State::Block1,
State::Block2,
State::Block3,
};
const int SORT_321[] = {
State::Block3,
State::Block2,
State::Block1,
};
///////////////////////////////////////
// GLOBAL STATE
const int *sortOrder = SORT_123; //< The sort order we are going to use
int position = 0; //< The reading head position (zero-based)
int nextIndex = 0; //< The next index to look for (zero-based)
State::Value state[BLOCK_COUNT] = { //< The state of the slots
State::Unknown,
State::Unknown,
State::Unknown,
};
///////////////////////////////////////
void scanState() {
Serial.println("Scanning");
delay(DELAY);
if (state[position] != State::Unknown) {
// Do nothing; we already know the current state of this slot
return;
}
// TODO: Replace this with the scanner code
delay(SENSOR_DELAY);
state[position] = (State::Value)(3 - (int(!digitalRead(sensor1)) + int(!digitalRead(sensor2)))); // check sensors and replace the state position and delete that line
delay(SENSOR_DELAY);
}
void moveLeft(int count) {
Serial.println ("Moving Left");
delay(DELAY);
// NOTE: Does no error checking; moves the rotor regardless of current position
const int AMOUNT = 58; // TODO: Find correct AMOUNT
rotor->step(AMOUNT * count, BACKWARD, SINGLE); // may have to change single
// Update the position
position -= count;
}
void moveRight(int count) {
Serial.println("Moving Right");
delay(DELAY);
// NOTE: Does no error checking; moves the rotor regardless of current position
const int AMOUNT = 58; // TODO: Find correct AMOUNT
rotor->step(AMOUNT * count, FORWARD, SINGLE);
// Update the position
position += count;
}
void activatePiston() {
Serial.println("Piston");
delay(DELAY);
const int AMOUNT = 130; // TODO: Find correct AMOUNT
piston->step(AMOUNT, FORWARD, SINGLE);
piston->step(AMOUNT, BACKWARD, SINGLE);
// Update the state
state[position] = State::Empty;
// Update to search for the next block in the list
++nextIndex;
}
bool isNext(int position) {
// TODO: This can be done more elegantly to handle additional cases, but should work fine for our simple case
// eg: if the blocks are all block 2 versions, this will fail
return state[position] == sortOrder[nextIndex];
}
// Search to the left of the current position and check if the next block has already been scanned
// Moves to that position, and pistons out the block if found
// @return true if the next block was found, false otherwise
bool searchLeft() {
// Loop through the stored array to find if the next block has already been scanned
for (int i = 0; i < position; ++i) {
if (isNext(i)) {
moveLeft(position - i);
activatePiston();
return true;
}
}
return false;
}
///////////////////////////////////////
void setup() {
Serial.begin(9600); // Set up Serial library at 9600 bps
Serial.println("Starting...");
AFMS.begin(); // Create with the default frequency 1.6KHz
pinMode(sensor1, INPUT);
pinMode(sensor2, INPUT);
rotor->setSpeed(10); // 10 rpm
piston->setSpeed(10); // 10 rpm
// TODO: Choose the sort order from an RGB sensor
sortOrder = SORT_123;
}
void loop() {
while (nextIndex < BLOCK_COUNT) {
// Scan the current position if we don't already know what's in it
scanState();
if (!isNext(position)) {
// If this is not what we are looking for, move to the next one
// NOTE: We are always filling in the array from left to right, so this is always the correct direction
moveRight(1);
} else {
// Push out the current block
activatePiston();
// Check if the next block has already been scanned
while (searchLeft()) {
// `searchLeft` searches, backs up, and pistons for us
// So do nothing
}
}
}
if (nextIndex == BLOCK_COUNT) {
Serial.println("Complete!");
// Prevent outputting "Complete!" more than once
++nextIndex;
}
}