Flaws exist but nonetheless the robot does function decently where it is at now. A video of this is below consisting of scenarios each at a different angle of the store function being run (to coordinate 15,5), a home function being run (so the robot has to move back to the start position, otherwise it'll just go down and pick up straight away which is no fun), and then the get function (back to coordinate 15,5).
Images of the physical changes and current state are below (The little blue thing is a blue lego brick with a piece of thin steel double sided taped to it. This is meant to represent the fridge).
Aside from the physical updates the code has also changed. On top of a few small value tweaks, a store and get function have been added. These right now run off a coordinate following the function. Eg store 18 3. The other change is that now upon start up, the robot will run routines servo up and home so that it will automatically reset its position to 0,0.
The new code is below:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Wire.h> | |
#include <Servo.h> | |
int Xdir=6; // drive pin to X direction relay | |
int Ydir=4; // drive pin to Y direction relay | |
int Xenable=5; // drive pin to X enable relay | |
int Yenable=10; // drive pin to Y enable relay | |
int Xpulse=3; // input from X encoder | |
int Ypulse=2; // input from Y encoder | |
int Solenoid = 9; | |
int Xhome = 11; | |
int Yhome = 8; | |
boolean Xdirection=false; // true if motor forward / false if reverse | |
boolean Ydirection=false; // true if motor forward / false if reverse | |
Servo Lift; | |
int Xposition=0; // encoder count for X | |
int Yposition=0; // encoder count for Y | |
boolean Xtravel = false; | |
boolean Ytravel = false; | |
int OldXstate, OldYstate; // input state of encoder pins (HIGH,LOW) | |
String inputString = ""; | |
boolean stringComplete=false; | |
String cmd = ""; | |
int arg [4] = {0,0,0,0}; | |
int ArgIndex; | |
void setup() | |
{ | |
Serial.begin(9600); | |
Serial.setTimeout(2); | |
inputString.reserve(200); | |
Serial.println(" Automated Gantry Warehouse"); | |
pinMode(Xdir, OUTPUT); | |
pinMode(Ydir, OUTPUT); | |
pinMode(Xenable, OUTPUT); | |
pinMode(Yenable, OUTPUT); | |
pinMode(Solenoid,OUTPUT); | |
pinMode(Xpulse,INPUT); | |
pinMode(Ypulse,INPUT); | |
pinMode(Xhome,INPUT); | |
pinMode(Yhome,INPUT); | |
digitalWrite(Solenoid,LOW); | |
Lift.attach(7); | |
Lift.write(128); | |
OldXstate = digitalRead(Xpulse); // get state of encoder inputs | |
OldYstate = digitalRead(Ypulse); // ... | |
ServoUp(); | |
GoHome(); | |
} | |
void loop(){ | |
// readY(); | |
// serialEvent(); | |
CheckEncoders(); | |
if (stringComplete){ | |
HandleCommand(); | |
inputString=""; | |
stringComplete=false; | |
} | |
} | |
void Home(){ | |
MoveTo(0,0); | |
} | |
void MoveTo(int x, int y){ | |
// if ((x < 0) || (y < 0) || (x > 40) || (y > 40)){ | |
// Serial.println("XY commands out of bounds"); | |
// return; | |
// } | |
Serial.println(y); | |
if (x !=Xposition){ | |
if (x > Xposition) XForward(); | |
if (x < Xposition) XReverse(); | |
} | |
while (Xposition !=x){ | |
CheckEncoders(); | |
ShowEncoders(); | |
} | |
XStop(); | |
ShowEncoders(); | |
delay (1000); | |
// return; | |
// ShowEncoders(); | |
// delay (2000); | |
if (y != Yposition){ | |
if (y > Yposition) YForward(); | |
if (y < Yposition) YReverse(); | |
} | |
ShowEncoders(); | |
while (y !=Yposition){ | |
CheckEncoders(); | |
ShowEncoders(); | |
} | |
YStop(); | |
ShowEncoders(); | |
} | |
void PickUp(){ | |
MoveTo(arg[0], arg[1]); | |
} | |
void GetFridge(){ | |
MoveTo(arg[0],arg[1]); | |
ServoDown(); | |
delay(400); | |
SolenoidOn(); | |
delay(300); | |
ServoUp(); | |
delay(200); | |
GoHome(); | |
ServoDown(); | |
SolenoidOff(); | |
delay(200); | |
ServoUp(); | |
} | |
void StoreFridge(){ | |
GoHome(); | |
ServoDown(); | |
delay(200); | |
SolenoidOn(); | |
delay(300); | |
ServoUp(); | |
delay(200); | |
MoveTo(arg[0],arg[1]); | |
ServoDown(); | |
SolenoidOff(); | |
delay(400); | |
ServoUp(); | |
} | |
void GoHome(){ | |
if (digitalRead(Xhome) == HIGH) { | |
XReverse(); | |
while(digitalRead(Xhome) == HIGH){ | |
CheckEncoders(); | |
} | |
XStop(); | |
// Xposition==0; | |
} | |
if (digitalRead(Yhome) == LOW) return; | |
YReverse(); | |
while(digitalRead(Yhome) == HIGH){ | |
CheckEncoders(); | |
} | |
YStop(); | |
// Yposition==0; | |
ResetEncoders(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void HandleCommand(){ | |
ParseInput(); | |
if (cmd == "xf") XForward(); | |
if (cmd == "xs") XStop(); | |
if (cmd == "xr") XReverse(); | |
if (cmd == "yf") YForward(); | |
if (cmd == "ys") YStop(); | |
if (cmd == "yr") YReverse(); | |
if (cmd == "se") ShowEncoders(); | |
if (cmd == "xy") PickUp(); | |
if (cmd == "re") ResetEncoders(); | |
if (cmd == "servo") DriveServo(); | |
if (cmd == "solon") SolenoidOn(); | |
if (cmd == "soloff") SolenoidOff(); | |
if (cmd == "home") GoHome(); | |
if (cmd == "sw") ShowSwitches(); | |
if (cmd == "su") ServoUp(); | |
if (cmd == "sd") ServoDown(); | |
if (cmd == "get") GetFridge(); | |
if (cmd == "store") StoreFridge(); | |
} | |
// from the serial input separate all arguments | |
void ParseInput(){ | |
Serial.println(inputString); | |
int space, slash; | |
for(int x = 0; x < 4; x++){ // flush the last args | |
arg[x] = 0; | |
} | |
ArgIndex = 0; // reset number of args to zero | |
space=inputString.indexOf(' '); | |
slash = inputString.indexOf('\n'); | |
inputString = inputString.substring(0,slash); | |
cmd = inputString.substring(0,space); | |
inputString = inputString.substring(space+1,slash); | |
while (inputString.indexOf(' ') > 0){ | |
space = inputString.indexOf(' '); | |
arg[ArgIndex] = inputString.substring(0,space).toInt(); | |
inputString = inputString.substring(space+1,inputString.length()); | |
ArgIndex++; | |
} | |
arg[ArgIndex] = inputString.toInt(); | |
} | |
void serialEvent(){ | |
// Serial.println("l"); | |
while(Serial.available()){ | |
// Serial.println("d"); | |
char inChar=(char)Serial.read(); | |
inputString += inChar; | |
// Serial.println(inputString); | |
if(inChar=='\n'){ | |
stringComplete=true; | |
// Serial.println("complete"); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void ReadY(){ | |
//Y = digitalRead(Ypulse); | |
} | |
void CheckEncoders(){ | |
int X,Y; | |
X = digitalRead(Xpulse); | |
Y = digitalRead(Ypulse); | |
// Serial.print(Xposition); | |
// Serial.print(" "); | |
// Serial.println(Yposition); | |
// delay(200); | |
if (OldXstate == LOW){ | |
if(X ==HIGH){ | |
if (Xdirection) Xposition++; | |
if (!Xdirection) Xposition--; | |
OldXstate = X; | |
goto CheckY; | |
} | |
} | |
if (OldXstate == HIGH){ | |
if (X == LOW){ | |
if (Xdirection) Xposition++; | |
if (!Xdirection) Xposition--; | |
OldXstate = LOW; | |
} | |
} | |
CheckY: | |
if (OldYstate == LOW){ | |
if(Y ==HIGH){ | |
if (Ydirection) Yposition++; | |
if (!Ydirection) Yposition--; | |
OldYstate = Y; | |
// Serial.println(Yposition); | |
return; | |
} | |
} | |
if (OldYstate == HIGH){ | |
if (Y == LOW){ | |
if (Ydirection) Yposition++; | |
if (!Ydirection) Yposition--; | |
OldYstate = LOW; | |
// Serial.println(Yposition); | |
} | |
} | |
} | |
// used in serial to show encoder counts | |
void ShowEncoders(){ | |
Serial.print("X= "); | |
Serial.print(Xposition); | |
Serial.print( " Y= "); | |
Serial.println(Yposition); | |
} | |
void PrintPosition(){ | |
Serial.print(Xposition); | |
Serial.print(" "); | |
Serial.println(Yposition); | |
} | |
void ResetEncoders(){ | |
Xposition = 0; | |
Yposition = 0; | |
Serial.println("Encoders reset"); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void SetXForward(){ | |
digitalWrite(Xdir,HIGH); | |
Xdirection= true; | |
} | |
void SetXReverse(){ | |
digitalWrite(Xdir,LOW); | |
Xdirection = false; | |
} | |
void XForward(){ | |
Xdirection=true; | |
digitalWrite(Xenable,LOW); | |
delay(30); | |
digitalWrite(Xdir,HIGH); | |
digitalWrite(Xenable,HIGH); | |
} | |
void YForward(){ | |
Ydirection=true; | |
digitalWrite(Yenable,LOW); | |
delay(30); | |
digitalWrite(Ydir,HIGH); | |
digitalWrite(Yenable,HIGH); | |
} | |
void XReverse(){ | |
Xdirection=false; | |
digitalWrite(Xenable,LOW); | |
delay(30); | |
digitalWrite(Xdir,LOW); | |
digitalWrite(Xenable,HIGH); | |
} | |
void YReverse(){ | |
Ydirection=false; | |
digitalWrite(Yenable,LOW); | |
delay(30); | |
digitalWrite(Ydir,LOW); | |
digitalWrite(Yenable,HIGH); | |
} | |
void XStop(){ | |
digitalWrite(Xenable,LOW); | |
digitalWrite(Xdir,LOW); | |
Xtravel = false; | |
} | |
void YStop(){ | |
digitalWrite(Yenable,LOW); | |
digitalWrite(Ydir,LOW); | |
Ytravel = false; | |
} | |
void Test(){ | |
XForward(); | |
delay(1250); | |
XStop(); | |
delay(1000); | |
XReverse(); | |
delay(1250); | |
XStop(); | |
delay(1000); | |
YForward(); | |
delay(500); | |
YStop(); | |
delay(1000); | |
YReverse(); | |
delay(500); | |
YStop(); | |
delay(1000); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void DriveServo(){ | |
Lift.write(arg[0]); | |
} | |
void ServoDown(){ | |
int x; | |
for(x=70;x < 134;x++){ | |
Lift.write(x); | |
delay(20); | |
} | |
} | |
void ServoUp(){ | |
int x; | |
for(x=134;x > 71; x--){ | |
Lift.write(x); | |
delay(20); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void SolenoidOn(){ | |
digitalWrite(Solenoid,HIGH); | |
} | |
void SolenoidOff(){ | |
digitalWrite(Solenoid,LOW); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void ShowSwitches(){ | |
/* | |
if (digitalRead(Xhome) == LOW) | |
Serial.println("X is home"); | |
else | |
Serial.println("X is NOT home"); | |
if (digitalRead(Yhome) == LOW) | |
Serial.println("Y is home"); | |
else | |
Serial.println("Y is NOT home"); */ | |
Serial.println(digitalRead(Xhome)); | |
Serial.println(digitalRead(Yhome)); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void readY(){ | |
Serial.println(digitalRead(Ypulse)); | |
} |
Whilst blogging this, I have only been producing documentation for my IPT project. The user manual for this version as well as a few diagrams are below:
USER MANUAL:
Manual Control: This is done by use of a number of in-built commands stored in an array. When these commands are entered into the serial input, they will execute a routine which is assigned to that command and perform an action. These are in the table below (“ “) means a value must be written).
Automated Control:
CONTEXT DIAGRAM:
BLOCK DIAGRAM:
USER MANUAL:
Manual Control: This is done by use of a number of in-built commands stored in an array. When these commands are entered into the serial input, they will execute a routine which is assigned to that command and perform an action. These are in the table below (“ “) means a value must be written).
Command
|
Routine
|
Function
|
xf
|
XForward()
|
Move X-axis
forward
|
xs
|
XStop()
|
Stop X-axis
movement
|
xr
|
XReverse()
|
Move X-axis
backwards
|
yf
|
YForward()
|
Move Y-axis
forward
|
ys
|
YStop()
|
Stop Y-axis
movement
|
yr
|
YReverse()
|
Move Y-axis
backwards
|
se
|
ShowEncoders()
|
Print the
current coordinates (in the form “x” “y”)
|
re
|
ResetEncoders()
|
Reset the
coordinate value to 0,0
|
xy “ “ “ “
|
PickUp()
|
Move to the
written x (input value in first “ “) and y coordinate (input value in second
“ “)
IMPORTANT:
Only values between 0 and 20 for x axis. Only values between 0 and 10 for y
axis.
|
servo “ “
|
DriveServo()
|
Move servo to
position “ “. This lowers and raises the electromagnet (The Z-Axis)
IMPORTANT:
Only values between 60 (highest point) and 230 (lowest point) should be
inputted.
|
solon
|
SolenoidOn()
|
Turn
electromagnet on.
|
soloff
|
SolenoidOff()
|
Turn
electromagnet off.
|
home
|
Home()
|
Move x and y
axis back to starting position (0,0)
|
Automated Control:
Storing:
To store an item, you must tell the robot through the serial
monitor input that you have an item in the docking bay which must be stored. To
do this we enter the command Store.
This tells the robot that it is going to the docking bay, and storing an item in
an available space.
However, in accordance to the old layout of storage, each
row will be dedicated to a certain model of fridge or freezer. Thus, you must
also tell the robot, what row and column the fridge is being stored. This can
be done by adding a space and then inputting an x y coordinate after.
The final resulting input line
could for example be:
Store 15 6
Once this is typed into the input,
press enter on the keyboard or click send to initiate the command. From here, the robot will complete the
storing process.
Retrieving:
The retrieving process is
conducted almost exactly the same as the storing process. Instead of the store
command being typed into the serial input, type Get. This will tell the system it must retrieve an item and bring
it back to the docking bay. However, you also need to input which model you
wish to retrieve. To do this after a space, type the x y coordinate of the item
you wish to retrieve.
The final resulting input line
could for example be:
Get 15 6
Once it is typed, press enter or
click send to start the retrieval. From here the robot will do everything else.
CONTEXT DIAGRAM:
BLOCK DIAGRAM:
MASTER CIRCUIT:
The robot still hasn't got all the functionality I wanted so this Sunday I will begin the making of version 2.0. This will most probably have the exact same hardware and circuitry (possibly a few modifications) but will most significantly have a new structure built out of aluminium with the perfect tension for the timing belts and an inventory function which works off an item's stored location not a coordinate.
The robot still hasn't got all the functionality I wanted so this Sunday I will begin the making of version 2.0. This will most probably have the exact same hardware and circuitry (possibly a few modifications) but will most significantly have a new structure built out of aluminium with the perfect tension for the timing belts and an inventory function which works off an item's stored location not a coordinate.
Goddammit Daniel, give me GitHub's syntax highlighting.
ReplyDeleteLike, what was the point of uploading it to Gist?