Tacobot
Voice controlled bluetooth
taco building -bot
..as Nature intended.

An attempt was made.


Arduino Uno
A4988 Motor Controllers (3)
TIP120 (2) or Dual Replay Module
HC-05 Bluetooth Module
Nema 17 Stepper Motor (2)
28BYJ-48 Stepper Motor
MG996R Servo
MG90S Servo (2)
5V Liquid Pump (2)
One Way Value (2)
Photoresistor
220 Resistor (2)
Lever Switch
Neopixels
12V to 5V Voltage Divider (2)
12V 30W Power Supply
Ball Bearings
Scavenged 3D printer parts


Notations
1. Could and should have made it smaller.
2. Limited item options to 9 (+1) as prototype.
3. Intended to dev tortilla conveyor (time restrictions)
4. Lag in bluetooth feedback inspires a cache coding.
5. Natural is a terrible PLA for display.
6. Dev'd app on MIT App Inventor (time restrictions)
7. Wet food is sticky ..who knew?! ~(o.o)~ Were there a second attempt ayh would design undulations in the dispenser tubes to reduce adhesion. Intended operation was single rotation (demonstrated in the dry run video) as opposed to dual rotation (demonstrated in the TVShow episode). Regret for having not resolved it for the primary video (time restrictions).
8. By far the most re-assemble-able project yet.







/*
tacobot (0.2)
vije miller
0 TX BT
1 RX BT
2 Sleep
3 (8) Servo Disp
4 (7) Neopixel Disp
5 (6) Servo Flip
6 Dir Y-Axis (14->A0)
7 (4) Servo Rotate
8 (3) Neopixel Plate
9 TIP120 1 (Sauce 1)
10 TIP120 2 (Sauce 2)
11 (2) Coms (AG 0) -->
12 (1) Coms (AG 1) -->
13 (0) Limit Plate
A0 (5) Light Sensor
15 Step Y-Axis
16 Dir X-Axis
17 Step X-Axis
18 Dir Disp
19 Step Disp

new_order[start(1), shell(1|2), order(1-9]
86 cancel
68 fire
77 add-on
99 repeat
*/

#include <AccelStepper.h>
#include <VarSpeedServo.h>
#include <FastLED.h>

// stepper data
// (driver, step, dir)
AccelStepper disp_step(1, 19, 18);
AccelStepper plate_x(1, 17, 16);
AccelStepper plate_y(1, 15, 6);
const int sleep = 2;
const int limit_plate = 13;
// long disp_homing = -1;
long plate_homing = -1;
// 1/4 steps 1600 2400
int disp_pos[9] = {0, 0, 400, 800, 1200, 1600, 2000, 2400, 2800};
// 1/4 1600 2400
const long plate_tort_one = 4250;
const long plate_feed = 3500;
const long plate_disp = 0;
// 1/4 13000 20000
const long plate_in = 0;
const long plate_out = 13500;

// servo data
VarSpeedServo servo_disp;
VarSpeedServo servo_rotate;
VarSpeedServo servo_flip;
const int servo_disp_pin = 3;
const int servo_rotate_pin = 7;
const int servo_flip_pin = 5;
const int s_r_forward = 107;
const int s_r_turn = 12;
const int s_f_down = 158;
const int s_f_up = 115;
const int s_d_top = 6;
const int s_d_bottom = 179;
const int sauce_one = 9;
const int sauce_two = 10;
const int s_d_sauce_one = 300;
const int s_d_sauce_two = 300;
int servo_disp_pos = 0;

// sensor data
const int light = A0;
const int light_covered = 380;
const int light_uncovered = 250;

// display data
#define num_leds_disp 7
CRGB leds_disp[num_leds_disp];
#define leds_pin_disp 4

#define num_leds_plate 2
CRGB leds_plate[num_leds_plate];
#define leds_pin_plate 8

// communication
int bt_int;
int start = 0;
int shell = 0;
int new_order[16];
int last_order[16];
int array_pos = 0;
int where = 0;
int when = 0;
int addon = 0;
const int com_one = 11;
const int com_two = 12;

void setup() {

Serial.begin(9600);
Serial.println("Tacobot: Loading");

// prevent a4988 float
pinMode(sleep, OUTPUT);
digitalWrite(sleep, LOW);
digitalWrite(15, LOW);
digitalWrite(17, LOW);
digitalWrite(19, LOW);
delay(500);

pinMode(limit_plate, INPUT_PULLUP);

pinMode(sauce_one, OUTPUT);
pinMode(sauce_two, OUTPUT);
digitalWrite(sauce_one, HIGH);
digitalWrite(sauce_two, HIGH);

pinMode(com_one, OUTPUT);
pinMode(com_two, OUTPUT);
digitalWrite(com_one, LOW);
digitalWrite(com_two, LOW);

Serial.println("Tacobot: Zeroing");

FastLED.addLeds<WS2812B, leds_pin_disp, RGB>(leds_disp, num_leds_disp);
FastLED.addLeds<WS2812B, leds_pin_plate, RGB>(leds_plate, num_leds_plate);
setAll_plate(0, 0, 0xff);
colorWipe(0, 0, 0xff, 100);

// home servos
// zero steppers
homing();

setAll_plate(0, 0, 0);
Serial.println("Tacobot: Ready");
}

void loop() {
// waiting display
colorWipe(0, 0, 0xff, 200);
colorWipe(0, 0, 0, 200);

// listen
if (Serial.available() > 0) {
bt_int = Serial.parseInt();
}

// add items until '68'
if (shell != 0 && bt_int != 0) {
// escape = 86
if (bt_int == 86) {

// clear array
for (byte p = 0; p < 16; p++) {
new_order[p] = 0;
}

// reset values
bt_int = 0;
shell = 0;
start = 0;
addon = 0;
where = 0;
when = 0;
array_pos = 0;
Serial.println("Tacobot: 86'd");
}

// fire order = 68
if (bt_int == 68) {
Serial.println("Tacobot: Fired");
fire_order();

// copy to last_order
memmove(last_order, new_order, 15);

// flush new_order
for (byte p = 0; p < 16; p++) {
new_order[p] = 0;
}
bt_int = 0;
shell = 0;
start = 0;
addon = 0;
where = 0;
when = 0;
array_pos = 0;
}
// com add-on = 77
if (bt_int == 77) {
addon = 1;
}

if (bt_int > 0 && bt_int < 15) {
Serial.println(bt_int);
new_order[array_pos] = bt_int;
array_pos++;
}
}

// repeat = 99
if (bt_int == 99) {
Serial.print("Tacobot: Reorder");
// copy last to new
memmove(new_order, last_order, 15);
fire_order();
// copy to last_order
memmove(last_order, new_order, 15);
// flush new_order
for (byte p = 0; p < 16; p++) {
new_order[p] = 0;
}
bt_int = 0;
shell = 0;
start = 0;
addon = 0;
where = 0;
when = 0;
array_pos = 0;
}

// actions reversed due to if sequence
// 1 = soft
// 2 = hard
if (start == 1 && shell == 0) {
if (bt_int == 1 || bt_int == 2) {
shell = bt_int;
if (bt_int == 1) {
Serial.println("Soft Shell");
} else if (bt_int == 2) {
Serial.println("Hard Shell");
}
}
}

// initiate process
// bt_int = 1
if (new_order[0] == 0 && start == 0 && bt_int == 1) {
start = 1;
Serial.println("Tacobot: Ordering");
}

// flush
bt_int = 0;
delay(1);
}

void fire_order() {
colorWipe(0, 0, 0, 100);
// signal shell
// soft now only
digitalWrite(com_one, HIGH);
delay(750);
digitalWrite(com_one, LOW);
// turn plate
servo_rotate.attach(servo_rotate_pin);
servo_flip.attach(servo_flip_pin);
servo_disp.attach(servo_disp_pin);
delay(50);
servo_rotate.write(s_r_turn, 60, true);
// move to rail
digitalWrite(sleep, HIGH);
setAll_plate(0, 0, 0xff);
plate_x.moveTo(plate_tort_one);
while (plate_x.distanceToGo() != 0) {
plate_x.run();
}
// extend plate
plate_y.moveTo(plate_out);
while (plate_y.distanceToGo() != 0) {
plate_y.run();
}
digitalWrite(sleep, LOW);
// wait for light sensor
while (analogRead(light) < light_covered) {
// ...
}
digitalWrite(sleep, HIGH);
delay(10);
// retract plate
plate_y.moveTo(plate_in);
while (plate_y.distanceToGo() != 0) {
plate_y.run();
}
// move back
plate_x.moveTo(plate_feed);
while (plate_x.distanceToGo() != 0) {
plate_x.run();
}
// turn and flip
servo_flip.write(s_f_up, 60, false);
servo_rotate.write(s_r_forward, 60, true);
delay(10);
// move to disp
plate_x.moveTo(plate_disp);
while (plate_x.distanceToGo() != 0) {
plate_x.run();
}
colorWipe(0, 0, 0xff, 100);
// cycle order
for (int q = 0; q < 15; q++) {
where = new_order[q];
// 0 = null
// 5 = sauce 1
// 10 = sauce 2 -> when = 5
if (where > 0 && where != 5 && where != 10) {
when = disp_pos[where];
disp_step.moveTo(when);
while (disp_step.distanceToGo() != 0) {
disp_step.run();
}
delay(750);
servo_drop_food();
delay(750);
} else if (where == 5 || where == 10) {
when = disp_pos[5];
disp_step.moveTo(when);
while (disp_step.distanceToGo() != 0) {
disp_step.run();
}
delay(800);
servo_drop_sauce(where);
delay(800);
}
delay(50);
}
// reset disp pos
disp_step.moveTo(0);
while (disp_step.distanceToGo() != 0) {
disp_step.run();
}
colorWipe(0, 0, 0, 100);
setAll_plate(0, 0, 0xff);
// move tray back
plate_x.moveTo(plate_feed);
while (plate_x.distanceToGo() != 0) {
plate_x.run();
}
// add on?
if (addon == 1) {
digitalWrite(com_two, HIGH);
delay(1000);
digitalWrite(com_two, LOW);
}
// extend tray
plate_y.moveTo(plate_out);
while (plate_y.distanceToGo() != 0) {
plate_y.run();
}
delay(10);
digitalWrite(sleep, LOW);
// wait for light sensor
while (analogRead(light) > light_uncovered) {
// ...
}
// flip down
servo_flip.write(s_f_down, 60, true);
digitalWrite(sleep, HIGH);
delay(10);
// retract tray
plate_y.moveTo(plate_in);
while (plate_y.distanceToGo() != 0) {
plate_y.run();
}
digitalWrite(sleep, LOW);
servo_disp.detach();
servo_flip.detach();
servo_rotate.detach();
}

void servo_drop_food() {
if (servo_disp_pos == 0) {
servo_disp.write(s_d_bottom, 200, true);
servo_disp_pos = 1;
} else if (servo_disp_pos == 1) {
servo_disp.write(s_d_top, 200, true);
servo_disp_pos = 0;
}
}

void servo_drop_sauce(int which) {
if (which == 5) {
digitalWrite(sauce_one, LOW);
delay(s_d_sauce_one);
digitalWrite(sauce_one, HIGH);
} else if (which == 10) {
digitalWrite(sauce_two, LOW);
delay(s_d_sauce_two);
digitalWrite(sauce_two, HIGH);
}
}

void showStrip() {
FastLED.show();
}

// neo disp
void setPixel_disp(int Pixel_disp, byte red_disp, byte green_disp, byte blue_disp) {
leds_disp[Pixel_disp].r = red_disp;
leds_disp[Pixel_disp].g = green_disp;
leds_disp[Pixel_disp].b = blue_disp;
}

void setAll_disp(byte red_disp, byte green_disp, byte blue_disp) {
for (int i = 0; i < num_leds_disp; i++ ) {
setPixel_disp(i, red_disp, green_disp, blue_disp);
}
showStrip();
}

void colorWipe(byte red_disp, byte green_disp, byte blue_disp, int SpeedDelay_disp) {
for (uint16_t i = 0; i < num_leds_disp; i++) {
setPixel_disp(i, red_disp, green_disp, blue_disp);
showStrip();
delay(SpeedDelay_disp);
}
}

// neo plate
void setPixel_plate(int Pixel_plate, byte red_plate, byte green_plate, byte blue_plate) {
leds_plate[Pixel_plate].r = red_plate;
leds_plate[Pixel_plate].g = green_plate;
leds_plate[Pixel_plate].b = blue_plate;
}

void setAll_plate(byte red_plate, byte green_plate, byte blue_plate) {
for (int j = 0; j < num_leds_plate; j++ ) {
setPixel_plate(j, red_plate, green_plate, blue_plate);
}
showStrip();
}

void homing() {
// home servos
servo_disp.attach(servo_disp_pin);
servo_rotate.attach(servo_rotate_pin);
servo_flip.attach(servo_flip_pin);
delay(100);
servo_disp.write(s_d_top, 200, true);
servo_rotate.write(s_r_forward, 60, true);
servo_flip.write(s_f_down, 60, true);
delay(500);
servo_disp.detach();
servo_flip.detach();
delay(1000);
Serial.println("Servos Adjusted");

// home disp
colorWipe(0, 0xff, 0, 100);
digitalWrite(sleep, HIGH);
delay(500);
disp_step.setCurrentPosition(0);
disp_step.setMaxSpeed(1600);
disp_step.setAcceleration(2400);
disp_step.moveTo(disp_pos[4]);
while (disp_step.distanceToGo() != 0) {
disp_step.run();
}
delay(500);
disp_step.moveTo(0);
while (disp_step.distanceToGo() != 0) {
disp_step.run();
}
digitalWrite(sleep, LOW);
colorWipe(0, 0, 0, 100);
delay(500);

// home plate
setAll_plate(0, 0xff, 0);
plate_x.setMaxSpeed(400.0);
plate_x.setAcceleration(400.0);
digitalWrite(sleep, HIGH);
delay(100);
while (digitalRead(limit_plate)) {
plate_x.moveTo(plate_homing);
plate_homing--;
plate_x.run();
}
plate_x.setCurrentPosition(0);
plate_x.setMaxSpeed(400.0);
plate_x.setAcceleration(400.0);
plate_homing = 1;
while (!digitalRead(limit_plate)) {
plate_x.moveTo(plate_homing);
plate_x.run();
plate_homing++;
}
plate_x.setCurrentPosition(0);
plate_x.setMaxSpeed(1600);
plate_x.setAcceleration(2400);
plate_feed_pos();
servo_rotate.write(s_r_forward, 60, true);
delay(250);
servo_rotate.detach();

plate_y.setCurrentPosition(0);
plate_y.setMaxSpeed(13000);
plate_y.setAcceleration(20000);
}

void plate_feed_pos() {
digitalWrite(sleep, HIGH);
plate_x.moveTo(plate_feed);
while (plate_x.distanceToGo() != 0) {
plate_x.run();
}
delay(50);
digitalWrite(sleep, LOW);
}


@pkvi
KE=½mv²
11,015 miters
1 miter today
197 tenons
Subscribe