Mechanical and Machine Design (Group Assignment)
Objective:
This week is collaborative effort with all our fellow students of the Node.
In this case, we as Ciudad de México FabLab, as a team, decided to try designing a time lapse rail for a Smart phone, whether is an iPhone or Android, and integrate a myriad of printed, cutted and existent pieces.
The main background is based on a typical rail with an automated system.
Research:
The original design, is a time-lapse rail with a timing belt as a dolly that moves along an axis, and the camera is attached to an articulated monopod; this raw model was developed in SOLIDWORKS®, as a simple short rail, translated from STEP to Rhino and IGES files, for compatibility.
Main specifications are:
Process of designing and development
Original model:
First iteration, sharing to a different platforms, from STEP to DXF, 3DM and IGS
First change, the Smart phone monopod with an external structure to fasten properly with clamps.
https://www.thingiverse.com/thing:2498739
First change, the Smart phone monopod with an external structure to fasten properly with clamps.
https://www.thingiverse.com/thing:2498739
Now the model looks slimmer and more elegant
Here, we are determining the envelope and applying physics principles to the bars, integrating the liitle stepper motor along the axis and the dolly.
Finally, a group revision... what if the dolly became a single 3d-printed box
How to avoid unexpected vibrations when moving...
And how to make it a lot more stable while moving
Then we manage to discuss what if the rods got a little bit more apart, to give way for the stepper motor to fit in the dolly, and secure the bearing along the rod.
Finally, the model evolved to a more static piece, using the main axis, setting in the beginning of the box all electronics.
A second prototype to see how it might work with this assembly
Now, we are working on the Code, based in this one:
https://create.arduino.cc/projecthub/cripps/arduino-hackhd-time-lapse-dolly-94f53e
/Time-lapse dolly/
#include <Keypad.h>
#define STEPS 4096
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
const byte LCDpin = 13;
const byte camTX = 18, camRX = 19; //pins to communicate with the camera
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//variables to store and verify user input
String filmDur = 0, sbf = 0, deg = 0;
boolean answerGiven = 0, userVerified = 0, inputValid = 0;
//stepper motors setup
const byte stepperSpeed = 10; //the higher the number the slower the stepper
const byte translate[4] = {9,10,11,12}; // pins for the translating stepper
const byte rotate[4] = {14,15,16,17}; // pins for rotating stepper
const boolean stepperSeq[8][4] = { //step sequence to move the motors
{1,0,0,1},
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,1,1,0},
{0,0,1,0},
{0,0,1,1},
{0,0,0,1}
};
void setup(){
pinMode(camTX, OUTPUT);
digitalWrite(camTX, HIGH); //Make sure the camera button is not grounded
pinMode(camRX, INPUT);
//set up stepper motors for translation and rotation
setupStepper(translate);
setupStepper(rotate);
pinMode(LCDpin,OUTPUT);
Serial.begin(19200);
resetLCD(LCDpin); //power on LCD
Serial.println("Welcome to the time-lapse dolly");
delay(2000);
standbyMode(camTX); //i only had to power on the camera here because
//otherwise the battery turned itself off due to lack of current being drawn
while(digitalRead(camRX) == LOW){
; //wait until camera verifies it is in standby mode
}
}
void loop(){
do {
Serial.println(" \n\n");
Serial.print("Duration of filming in hours: ");
filmDur = getData(2); //wait for input of 2 chars in length
do {
Serial.println(" \n\n");
Serial.print("How many secondsbetween shots:");
sbf = getData(2);
if(sbf.toInt() < 10){
Serial.println(" \n\n");
Serial.print("Minimum 15 seconds between shots");
delay(3000);
}
else {
inputValid = 1;
}
} while(inputValid == 0);
Serial.println(" \n\n");
Serial.print("How many degreesof rotation:");
deg = getData(3);
Serial.println(" \n\n");
Serial.print("OK! the sequencewill go for.... ");
delay(2000);
Serial.println(" \n\n");
Serial.print(filmDur);
Serial.print(" hours");
delay(2000);
Serial.println(" \n\n");
Serial.print("There will be ... ");
delay(2000);
Serial.println(" \n\n\n\n");
Serial.print(sbf);
Serial.print(" seconds between frames");
delay(2000);
Serial.println(" \n");
Serial.print("And the camera will rotate ");
delay(2000);
Serial.println(" \n\n\n");
Serial.print(deg);
Serial.print(" degrees");
delay(2000);
Serial.println(" \n\n");
Serial.print("Is this OK? * = YES # = NO ");
answerGiven = 0; //reset boolean in case it isn't the first time through
do {
char key = keypad.getKey();
if(key == '*'){ //if YES, mark input as verified by the user
userVerified = 1;
answerGiven = 1;
}
if(key == '#'){ //if NO, clear entries and start from the top
filmDur = 0;
sbf = 0;
deg = 0;
inputValid = 0;
answerGiven = 1;
}
} while(answerGiven == 0); //wait for a valid answer
} while (userVerified == 0); //if input is verified then continue
//begin time-lapse photography
Serial.println(" \n\n");
Serial.print("Initiating sequence...\n");
//calculate total frames in sequence
int totalFrames = filmDur.toInt() * 60 * 60 / sbf.toInt();
//calculate increment for the translation stepper
int incrementT = round(5 * STEPS / (float)totalFrames);
//calculate increment for the rotation stepper
float ratio = (float) deg.toInt() / 360;
int incrementR = round(STEPS * ratio / totalFrames);
//get out of standby mode before actually beginning photography
standbyMode(camTX);
while(digitalRead(camRX) == HIGH){
;
}
int i, nextStepT = 0, nextStepR = 0;
for(i = 1; i <= totalFrames; i++){
unsigned long time = millis(); //get time at beggining of iteration
shoot(camTX); //take a picture
Serial.println(" \n\n");
//calculate and display the percentage completion and hours remaining
int percentage = i / (float)totalFrames * 100;
Serial.print(percentage);
Serial.print("% complete");
Serial.println("\n");
int hrsLeft = round( (float)filmDur.toInt() * ( (100 - (float)percentage) / 100 ));
Serial.print( hrsLeft );
Serial.print(" hours left");
nextStepT = stepper(translate, incrementT, 1, nextStepT); //translate
nextStepR = stepper(rotate, incrementR, 1, nextStepR); //rotate
//subtract the time elapsed since the beggining of the iteration from
//the desired delay between frames, and then delay that resulting time
while(digitalRead(camRX) == HIGH){
; //wait for picture to save before moving on
}
while( ( millis() - time ) < ( sbf.toInt() * 1000 ) ){
;
}
}
Serial.print("done");
while(1){
;
}
}
void resetLCD(byte pin) {
digitalWrite(pin,LOW);
delay(500);
digitalWrite(pin,HIGH);
delay(2000); //LCD needs time to self-test
}
void standbyMode(byte pin){
digitalWrite(pin, LOW);
delay(2000);
digitalWrite(pin, HIGH);
}
void shoot(byte pin){
digitalWrite(pin, LOW);
delay(200);
digitalWrite(pin, HIGH);
}
String getData(int len){
//function that returns a string entered on the keypad of max length "len"
String data = 0;
while(data.length() < len) {
char key = keypad.getKey();
if (key){
if(key == '#' || key == '*'){
; //do not accept non-numeric characters
} else {
data += key; //concatenate character to input string
Serial.print(key); //print character
}
}
}
delay(500); //allow time so user can actually see his/her input before moving on
return data;
}
void setupStepper(const byte type[]){
//set all stepper pins to output
int i = 0;
for(i=0; i<4; i++){
pinMode(type[i], OUTPUT);
}
}
int stepper (const byte type[], int iterations, boolean dir, int lastStep){
int d = 0;
if(dir){ //dir = 1 means clockwise
while(iterations){
for(d = 0; d < 4; d ++){
digitalWrite(type[d], stepperSeq[lastStep][d]);
}
lastStep++;
if(lastStep > 7){
lastStep = 0;
}
iterations--;
delay(stepperSpeed);
}
}
else { //dir = 0 means counterclockwise
while(iterations){
for(d = 0; d < 4; d++){
digitalWrite(type[d], stepperSeq[lastStep][d]);
}
lastStep--;
if( lastStep < 0 ){
lastStep = 7;
}
iterations--;
delay(stepperSpeed);
}
}
return lastStep;
}