POSTS
Week 12: Machine Design
These are the repos for the cpp and javascript:
git@github.mit.edu:premila/eds_cuttlefish.git
git@github.mit.edu:premila/eds_ponyo.git
ponyo atsamd51j19/src/hunks/pins/hunk_pin_pa12_output.cpp
ponyo/atsamd51j19/src/build_bootstrap.h
PlatformIo and ponyo setup
Add hunk class (example code hunk_pin_pa12_output.h, hunk_pin_pa12_output.cpp) and add to build_bootstrap.h
Somehow make that cpp code on the board
Create .js code for hunks, under :cuttlefish/hunks/interface
Add hunks with inputs and outputs connected to toggle and errlight to output to LED
hunklist[hlc++] = "driver/errlight";
if (type == "driver/errlight"){
ret = new Hunk_ErrLight();
}
Writing Jake’s code to the module board:
(using linux is easiest)
Download platformio in visual studio code and open Jake’s repo called ponyo folder from platformio home (not visual studio). Then start debugging and fix the following things:
Run this command to change all “arduino.h” to “Arduino.h”
find . -type f -exec sed -i 's/<arduino.h>/<Arduino.h>/g' {} \;
Check if it worked by running this to search for any remaining “arduino.h”’s
grep -R arduino.h *
Look for this in the code. It’s important to do this otherwise things won’t compile. You need to comment out SERCOM5_2_Handler and SERCOM5_0_Handler.
// need to comment out arduino's instantiation of this,
// platformio keeps these things elsewhere,
// for (windows) this was (the .- proceeding the folder name means it's hidden)
// you'll have to make sure hidden files are exposed in your finder
// users/<me>/.platformio/packages/framework-arduinosam/variants/feature_m4/variant.cpp
Check your devices in platformio and if it doesn’t say 8031, go to cuttlefish/processes/vfpts.js and change the product ID to match whatever your device reads.
let pid = '8031'
To test things, I changed the name of one of Jake’s modules and then changed the name in the hunks list in the bootstrap file and tested if it updated on the GUI side.
Cuttlefish:
link - connecting the serial port hunk to your computer to interact with board
defining pins:
#define PUMP1_PIN 20
#define PUMP1_PORT PORT->Group[0]
#define PUMP2_PIN 21
#define PUMP2_PORT PORT->Group[0]
#define PUMP3_PIN 22
#define PUMP3_PORT PORT->Group[0]
#define PUMP4_PIN 23
#define PUMP4_PORT PORT->Group[0]
#define PUMP1_BM (uint32_t)(1 << PUMP1_PIN)
#define PUMP1_SETUP PUMP1_PORT.DIRSET.reg = PUMP1_BM
#define PUMP1_ON PUMP1_PORT.OUTCLR.reg = PUMP1_BM
#define PUMP1_OFF PUMP1_PORT.OUTSET.reg = PUMP1_BM
#define PUMP2_BM (uint32_t)(1 << PUMP2_PIN)
#define PUMP2_SETUP PUMP2_PORT.DIRSET.reg = PUMP2_BM
#define PUMP2_ON PUMP2_PORT.OUTCLR.reg = PUMP2_BM
#define PUMP2_OFF PUMP2_PORT.OUTSET.reg = PUMP2_BM
#define PUMP3_BM (uint32_t)(1 << PUMP3_PIN)
#define PUMP3_SETUP PUMP3_PORT.DIRSET.reg = PUMP3_BM
#define PUMP3_ON PUMP3_PORT.OUTCLR.reg = PUMP3_BM
#define PUMP3_OFF PUMP3_PORT.OUTSET.reg = PUMP3_BM
#define PUMP4_BM (uint32_t)(1 << PUMP4_PIN)
#define PUMP4_SETUP PUMP4_PORT.DIRSET.reg = PUMP4_BM
#define PUMP4_ON PUMP4_PORT.OUTCLR.reg = PUMP4_BM
#define PUMP4_OFF PUMP4_PORT.OUTSET.reg = PUMP4_BM
Added hunk to list in bootstrap
hunklist[hlc++] = "driver/pour";
if (type == "driver/pour"){
ret = new Hunk_Pour();
}
cuttlefish workflow:
- restore system
- little rascal just the x
- hardcoded array in saturn
toggle to turn on stepper motors
ad hoc/testpath -> saturn -> somewhere -> stepper motor
need to delay between moves
We (Harrison and I) created a state machine that transitions between pouring and moving in a javascript hunk to use in cuttlefish to set the workflow for our machine.
We created two outputs: one for the pump number we want to pour out of and one for the position we want our cup to be at.
// pumpState output -> microcontroller input
let pumpState = this.output('int32', 'pumpState', 0);
// stepperPosition output -> saturn posn input
let stepperPosition = this.output('array', 'stepperPosition', 0);
We initialized the drinking machine hunk:
this.init = () => {
this.log('hello drinking machine')
}
We have a dictionary mapping drink numbers to lists of the ratios/amount of each ingredient for each drink.
const dictDrinks = { //apparently you can't have integer keys
'0': [0], // a state to reset everything
'1': [1,1,2,2,2,4,5], // end with 5 so we go to the end
'2': [1,1,1,2,3,3,5],
'3': [2,2,2,3,3,4,4,4,5],
'4': [1,1,3,3,4,4,4,4,5]
};
We also created a dictionary for positions to move to via the stepper motor.
const dictPositions = { // Pass an array to Saturn
'0': [0,0,0], // far left
'1': [20,0,0], // under first pump
'2': [40,0,0], // under second pump
'3': [60,0,0], // under third pump
'4': [80,0,0], // under fourth pump
'5': [100,0,0],// far right
};
Here are our states:
const states = {
IDLE: 0,
GET_NEXT_ITEM: 1,
MOVE_STEPPER: 2,
MOVE_DELAY: 3,
POUR_DRINK: 4,
POUR_DELAY: 5
};
We used a delay technique to wait for different states to finish:
const delayInMillisecondsMove = 1000; //3 second
const delayInMillisecondsPour = 2000; //30 seconds
Here’s the list of drinks we can make for you!
const pairList = [
[0, 'Reset'],
[1, 'Mojito'],
[2, 'Manhattan'],
[3, 'Screwdriver'],
[4, 'Tropical Sunset']
];
This is the loop that switches between states:
this.loop = () => {
switch(state){
case states.IDLE:
// do nothing while idling
break;
case states.GET_NEXT_ITEM:
// check to see if there's anything left to grab
if (currentIngredient >= drinkList.length){ // nothing left to do!
state = states.IDLE;
console.log("Drink Complete");
break;
}
// pull the next drink
let oldMove = curMove; // check previous move to see if we've done it already
curMove = dictPositions[drinkList[currentIngredient]];
curPour = drinkList[currentIngredient];
console.log("Preparing ingredient " + currentIngredient);
currentIngredient++;
if (oldMove == curMove) { // if we've already moved the stepper here, don't do it again
state = states.POUR_DRINK;
}
state = states.MOVE_STEPPER;
break;
case states.MOVE_STEPPER:
stepperPosition.put(curMove); // move the stepper
console.log("Moving to " + curMove);
setTimeout(function() { // after 3 seconds, switch to pour state
state = states.POUR_DRINK;
}, delayInMillisecondsMove);
state = states.MOVE_DELAY;
break;
case states.MOVE_DELAY:
// do nothing while waiting for move to complete
break;
case states.POUR_DRINK:
if (curPour == 5){ // don't pour if we're at the end
state = states.IDLE;
console.log("At the end, no pour");
break;
}
console.log("Pouring " + curPour);
pumpState.put(curPour);
if (curPour == 0){ // there's nothing to pour
state = states.GET_NEXT_ITEM;
break;
}
setTimeout(function() { // after 30 seconds, switch to get
pumpState.put(0); // stop pouring after complete
state = states.GET_NEXT_ITEM;
}, delayInMillisecondsPour);
state = states.POUR_DELAY;
break;
case states.POUR_DELAY:
// do nothing while waiting for pour to complete
break;
}
We did a lot of testing and debugging in cuttlefish:
We created a drop down menu for drinks to choose from- this list outputs to the pump hunk and saturn itself. You can see the drinks being sent on the debug console.
Here’s the cuttlefish interface working with both the stepper motor moving and the drink being poured: (successful state machine!!!)
This is the console showing the order of events:
COMMENT/UNCOMMENT THESE THINGS TO PUSH FIRMWARE UPDATES TO DIFFERENT BOARDS!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #define BOOT_USB
// pick 'yer board
// #define BOARD_IS_BASIC
#define BOARD_IS_STEPPER
// #define BOARD_IS_ROUTER
//#define BOARD_IS_DLPCORE
#ifdef BOARD_IS_STEPPER
#define BUILD_INCLUDES_HUNK_STEPPER
#define BUILD_INCLUDES_HUNK_MDTODMSEG
#endif
#ifdef BOARD_IS_ROUTER
// it ain't
#undef IS_MODULE_V01
#define BUILD_INCLUDES_HUNK_COBSERIALA // ok
#define BUILD_INCLUDES_HUNK_COBSERIALB // ok
#define BUILD_INCLUDES_HUNK_COBSERIALC // ok
#define BUILD_INCLUDES_HUNK_COBSERIALD // ok
#define BUILD_INCLUDES_HUNK_COBSERIALE // ok
#define BUILD_INCLUDES_HUNK_COBSERIALF // ok
// also
#define BUILD_INCLUDES_HUNK_MDTODMSEG
#endif
I also worked on ideation at the beginning of the project including the design of the cup holder and how the system would work. (all whiteboarding)
I worked on system integration and putting all the pieces together as well as helped manage and make sure we had all the necessary parts (including ordering parts we didn’t make).
I also worked on all the testing and debugging using cuttlefish and fine tuning the final machine.