diff --git a/EggDuino.ino b/EggDuino.ino index e14a218..b3a0452 100644 --- a/EggDuino.ino +++ b/EggDuino.ino @@ -18,44 +18,55 @@ Thanks to my wife and my daughter for their patience. :-) 1 collision control via penMin/penMax 2 implement homing sequence via microswitch or optical device */ -#include "AccelStepper.h" -//#include "libs\AccelStepper.h" // nice lib from http://www.airspayce.com/mikem/arduino/AccelStepper/ + +#include "AccelStepper.h" // nice lib from http://www.airspayce.com/mikem/arduino/AccelStepper/ #include #include "SerialCommand.h" //nice lib from Stefan Rado, https://github.com/kroimon/Arduino-SerialCommand #include +#include "button.h" -#define initSting "EBBv13_and_above Protocol emulated by Eggduino-Firmware V1.4" -//Rotational Stepper +#define initSting "EBBv13_and_above Protocol emulated by Eggduino-Firmware V1.6" +//Rotational Stepper: #define step1 11 #define dir1 10 #define enableRotMotor 9 #define rotMicrostep 16 //MicrostepMode, only 1,2,4,8,16 allowed, because of Integer-Math in this Sketch -//Pen Stepper +//Pen Stepper: #define step2 8 #define dir2 7 #define enablePenMotor 6 #define penMicrostep 16 //MicrostepMode, only 1,2,4,8,16 allowed, because of Integer-Math in this Sketch -//Servo - #define servoPin 3 -// PRG button - #define prgButton 2 -// pen up/down button - #define penToggleButton 12 -// motors enable button - #define motorsButton 4 + + #define servoPin 3 //Servo + +// EXTRAFEATURES - UNCOMMENT TO USE THEM ------------------------------------------------------------------- + +// #define prgButton 2 // PRG button +// #define penToggleButton 12 // pen up/down button +// #define motorsButton 4 // motors enable button + +// #define CommandSMQB +//----------------------------------------------------------------------------------------------------------- #define penUpPosEEAddress ((uint16_t *)0) #define penDownPosEEAddress ((uint16_t *)2) - #define debounceDelay 50 - //make Objects AccelStepper rotMotor(1, step1, dir1); AccelStepper penMotor(1, step2, dir2); Servo penServo; SerialCommand SCmd; - -// Variables... be careful, by messing around here, evrything has a reason and crossrelations... + //create Buttons + #ifdef prgButton + Button prgButtonToggle(prgButton, setprgButtonState); + #endif + #ifdef penToggleButton + Button penToggle(penToggleButton, doTogglePen); + #endif + #ifdef motorsButton + Button motorsToggle(motorsButton, toggleMotors); + #endif +// Variables... be careful, by messing around here, everything has a reason and crossrelations... int penMin=0; int penMax=0; int penUpPos=5; //can be overwritten from EBB-Command SC @@ -72,46 +83,8 @@ Thanks to my wife and my daughter for their patience. :-) uint8_t penStepCorrection = 16/penMicrostep ; //devide EBB-Coordinates by this factor to get EGGduino-Steps float rotSpeed=0; float penSpeed=0; // these are local variables for Function SteppermotorMove-Command, but for performance-reasons it will be initialized here - int motorsEnabled = 0; - - typedef void (*ActionCb)(void); - - class Button { - public: - Button(byte p, ActionCb a): debounce(0), state(1), lastState(1), action(a), pin(p) {}; - - void check() { - byte b = digitalRead(pin); - long t = millis(); - - if (b != lastState) { - debounce = t; - } - - if ((t - debounce) > debounceDelay) { - if (b != state) { - state = b; - - if (!state) { - (*action)(); - } - } - } - - lastState = b; - } - - private: - long debounce; - byte state:1; - byte lastState:1; - byte pin; - ActionCb action; - }; - - Button penToggle(penToggleButton, doTogglePen); - Button motorsToggle(motorsButton, toggleMotors); - + boolean motorsEnabled = 0; + void setup() { Serial.begin(9600); makeComInterface(); @@ -119,9 +92,22 @@ void setup() { } void loop() { - SCmd.readSerial(); - penToggle.check(); - motorsToggle.check(); - if( 0 == digitalRead(prgButton)) - prgButtonState = 1; + if ( penMotor.distanceToGo() || rotMotor.distanceToGo() ) { + penMotor.runSpeedToPosition(); // Moving.... moving... moving.... + rotMotor.runSpeedToPosition(); + } + + SCmd.readSerial(); + + #ifdef penToggleButton + penToggle.check(); + #endif + + #ifdef motorsButton + motorsToggle.check(); + #endif + + #ifdef prgButton + prgButtonToggle.check(); + #endif } diff --git a/Functions.ino b/Functions.ino index 16817af..24009fa 100644 --- a/Functions.ino +++ b/Functions.ino @@ -5,7 +5,9 @@ void makeComInterface(){ SCmd.addCommand("SC",stepperModeConfigure); SCmd.addCommand("SP",setPen); SCmd.addCommand("SM",stepperMove); - SCmd.addCommand("SMQB",stepperMoveQueryButton); // composite function enabling smooth movement + #ifdef CommandSMQB + SCmd.addCommand("SMQB",stepperMoveQueryButton); // composite function enabling smooth movement + #endif SCmd.addCommand("SE",ignore); SCmd.addCommand("TP",togglePen); SCmd.addCommand("PO",ignore); //Engraver command, not implemented, gives fake answer @@ -32,8 +34,8 @@ void queryPen() { void queryButton() { Serial.print(String(prgButtonState) +"\r\n"); - prgButtonState = 0; sendAck(); + prgButtonState = 0; } void queryLayer() { @@ -87,109 +89,60 @@ void stepperMove() { uint16_t duration=0; //in ms int penStepsEBB=0; //Pen int rotStepsEBB=0; //Rot + while ( penMotor.distanceToGo() || rotMotor.distanceToGo() ) { + penMotor.runSpeedToPosition(); // Moving.... moving... moving.... + rotMotor.runSpeedToPosition(); + } if (!parseSMArgs(&duration, &penStepsEBB, &rotStepsEBB)) { sendError(); return; } - if ( (penStepsEBB==0) && (rotStepsEBB==0) ) { - delay(duration); - sendAck(); - return; - } - - doMove(duration, penStepsEBB, rotStepsEBB); sendAck(); -} - -void stepperMoveQueryButton() { - uint16_t duration=0; //in ms - int penStepsEBB=0; //Pen - int rotStepsEBB=0; //Rot - - if (!parseSMArgs(&duration, &penStepsEBB, &rotStepsEBB)) { - sendError(); - return; - } - + if ( (penStepsEBB==0) && (rotStepsEBB==0) ) { delay(duration); - queryButton(); + //sendAck(); return; } - // sending ACK before actual move to allow buffering - queryButton(); doMove(duration, penStepsEBB, rotStepsEBB); + //sendAck(); } -bool parseSMArgs(uint16_t *duration, int *penStepsEBB, int *rotStepsEBB) { - char *arg1; - char *arg2; - char *arg3; - arg1 = SCmd.next(); - if (arg1 != NULL) { - *duration = atoi(arg1); - arg2 = SCmd.next(); - } - if (arg2 != NULL) { - *penStepsEBB = atoi(arg2); - arg3 = SCmd.next(); - } - if (arg3 != NULL) { - *rotStepsEBB = atoi(arg3); - - return true; - } +#ifdef CommandSMQB + void stepperMoveQueryButton() { + uint16_t duration=0; //in ms + int penStepsEBB=0; //Pen + int rotStepsEBB=0; //Rot - return false; -} + if (!parseSMArgs(&duration, &penStepsEBB, &rotStepsEBB)) { + sendError(); + return; + } -void doMove(uint16_t duration, int penStepsEBB, int rotStepsEBB) { - motorsOn(); + if ( (penStepsEBB==0) && (rotStepsEBB==0) ) { + delay(duration); + queryButton(); + return; + } - if( (1 == rotStepCorrection) && (1 == penStepCorrection) ){ // if coordinatessystems are identical - //set Coordinates and Speed - rotMotor.move(rotStepsEBB); - rotMotor.setSpeed( abs( (float)rotStepsEBB * (float)1000 / (float)duration ) ); - penMotor.move(penStepsEBB); - penMotor.setSpeed( abs( (float)penStepsEBB * (float)1000 / (float)duration ) ); - } else { - //incoming EBB-Steps will be multiplied by 16, then Integer-maths is done, result will be divided by 16 - // This make thinks here really complicated, but floating point-math kills performance and memory, believe me... I tried... - long rotSteps = ( (long)rotStepsEBB * 16 / rotStepCorrection) + (long)rotStepError; //correct incoming EBB-Steps to our microstep-Setting and multiply by 16 to avoid floatingpoint... - long penSteps = ( (long)penStepsEBB * 16 / penStepCorrection) + (long)penStepError; + // sending ACK before actual move to allow buffering + queryButton(); + doMove(duration, penStepsEBB, rotStepsEBB); + } +#endif - int rotStepsToGo = (int) (rotSteps/16); //Calc Steps to go, which are possible on our machine - int penStepsToGo = (int) (penSteps/16); - - rotStepError = (long)rotSteps - ((long) rotStepsToGo * (long)16); // calc Position-Error, if there is one - penStepError = (long)penSteps - ((long) penStepsToGo * (long)16); - - long temp_rotSpeed = ((long)rotStepsToGo * (long)1000 / (long)duration ); // calc Speed in Integer Math - long temp_penSpeed = ((long)penStepsToGo * (long)1000 / (long)duration ) ; - - float rotSpeed= (float) abs(temp_rotSpeed); // type cast - float penSpeed= (float) abs(temp_penSpeed); - - //set Coordinates and Speed - rotMotor.move(rotStepsToGo); // finally, let us set the target position... - rotMotor.setSpeed(rotSpeed); // and the Speed! - penMotor.move(penStepsToGo); - penMotor.setSpeed( penSpeed ); - } - - while ( penMotor.distanceToGo() || rotMotor.distanceToGo() ) { - penMotor.runSpeedToPosition(); // Moving.... moving... moving.... - rotMotor.runSpeedToPosition(); - } -} void setPen(){ int cmd; int value; char *arg; + while ( penMotor.distanceToGo() || rotMotor.distanceToGo() ) { + penMotor.runSpeedToPosition(); // Moving.... moving... moving.... + rotMotor.runSpeedToPosition(); + } arg = SCmd.next(); if (arg != NULL) { cmd = atoi(arg); @@ -202,7 +155,6 @@ void setPen(){ case 1: penServo.write(penDownPos); penState=penDownPos; - //Serial.println("case 1"); break; default: @@ -212,14 +164,14 @@ void setPen(){ char *val; val = SCmd.next(); if (val != NULL) { - value = atoi(val); - // Serial.println("delayvalue"); - delay(value); - sendAck(); - } - if (val==NULL && arg !=NULL) - delay(500); - sendAck(); + value = atoi(val); + sendAck(); + delay(value); + } + if (val==NULL && arg !=NULL) { + sendAck(); + delay(500); + } // Serial.println("delay"); if (val==NULL && arg ==NULL) sendError(); @@ -228,16 +180,19 @@ void setPen(){ void togglePen(){ int value; char *arg; + while ( penMotor.distanceToGo() || rotMotor.distanceToGo() ) { + penMotor.runSpeedToPosition(); // Moving.... moving... moving.... + rotMotor.runSpeedToPosition(); + } arg = SCmd.next(); if (arg != NULL) value = atoi(arg); else value = 500; - doTogglePen(); - - delay(value); - sendAck(); + doTogglePen(); + sendAck(); + delay(value); } void doTogglePen() { @@ -289,26 +244,6 @@ void enableMotors(){ } } -void motorsOff() { - digitalWrite(enableRotMotor, HIGH); - digitalWrite(enablePenMotor, HIGH); - motorsEnabled = 0; -} - -void motorsOn() { - digitalWrite(enableRotMotor, LOW) ; - digitalWrite(enablePenMotor, LOW) ; - motorsEnabled = 1; -} - -void toggleMotors() { - if (motorsEnabled) { - motorsOff(); - } else { - motorsOn(); - } -} - void stepperModeConfigure(){ int cmd; int value; diff --git a/Helper_Functions.ino b/Helper_Functions.ino index a8f45b4..371f958 100644 --- a/Helper_Functions.ino +++ b/Helper_Functions.ino @@ -6,9 +6,18 @@ void initHardware(){ pinMode(enableRotMotor, OUTPUT); pinMode(enablePenMotor, OUTPUT); - pinMode(prgButton, INPUT_PULLUP); - pinMode(penToggleButton, INPUT_PULLUP); - pinMode(motorsButton, INPUT_PULLUP); + + #ifdef prgButton + pinMode(prgButton, INPUT_PULLUP); + #endif + + #ifdef penToggleButton + pinMode(penToggleButton, INPUT_PULLUP); + #endif + + #ifdef motorsButton + pinMode(motorsButton, INPUT_PULLUP); + #endif rotMotor.setMaxSpeed(2000.0); rotMotor.setAcceleration(10000.0); @@ -41,3 +50,90 @@ void inline sendError(){ Serial.print("unknown CMD\r\n"); } +void motorsOff() { + digitalWrite(enableRotMotor, HIGH); + digitalWrite(enablePenMotor, HIGH); + motorsEnabled = 0; +} + +void motorsOn() { + digitalWrite(enableRotMotor, LOW) ; + digitalWrite(enablePenMotor, LOW) ; + motorsEnabled = 1; +} + +void toggleMotors() { + if (motorsEnabled) { + motorsOff(); + } else { + motorsOn(); + } +} + +bool parseSMArgs(uint16_t *duration, int *penStepsEBB, int *rotStepsEBB) { + char *arg1; + char *arg2; + char *arg3; + arg1 = SCmd.next(); + if (arg1 != NULL) { + *duration = atoi(arg1); + arg2 = SCmd.next(); + } + if (arg2 != NULL) { + *penStepsEBB = atoi(arg2); + arg3 = SCmd.next(); + } + if (arg3 != NULL) { + *rotStepsEBB = atoi(arg3); + + return true; + } + + return false; +} + +void doMove(uint16_t duration, int penStepsEBB, int rotStepsEBB) { + if (!motorsEnabled) { + motorsOn(); + } + if( (1 == rotStepCorrection) && (1 == penStepCorrection) ){ // if coordinatessystems are identical + //set Coordinates and Speed + rotMotor.move(rotStepsEBB); + rotMotor.setSpeed( abs( (float)rotStepsEBB * (float)1000 / (float)duration ) ); + penMotor.move(penStepsEBB); + penMotor.setSpeed( abs( (float)penStepsEBB * (float)1000 / (float)duration ) ); + } else { + //incoming EBB-Steps will be multiplied by 16, then Integer-maths is done, result will be divided by 16 + // This make thinks here really complicated, but floating point-math kills performance and memory, believe me... I tried... + long rotSteps = ( (long)rotStepsEBB * 16 / rotStepCorrection) + (long)rotStepError; //correct incoming EBB-Steps to our microstep-Setting and multiply by 16 to avoid floatingpoint... + long penSteps = ( (long)penStepsEBB * 16 / penStepCorrection) + (long)penStepError; + + int rotStepsToGo = (int) (rotSteps/16); //Calc Steps to go, which are possible on our machine + int penStepsToGo = (int) (penSteps/16); + + rotStepError = (long)rotSteps - ((long) rotStepsToGo * (long)16); // calc Position-Error, if there is one + penStepError = (long)penSteps - ((long) penStepsToGo * (long)16); + + long temp_rotSpeed = ((long)rotStepsToGo * (long)1000 / (long)duration ); // calc Speed in Integer Math + long temp_penSpeed = ((long)penStepsToGo * (long)1000 / (long)duration ) ; + + float rotSpeed= (float) abs(temp_rotSpeed); // type cast + float penSpeed= (float) abs(temp_penSpeed); + + //set Coordinates and Speed + rotMotor.move(rotStepsToGo); // finally, let us set the target position... + rotMotor.setSpeed(rotSpeed); // and the Speed! + penMotor.move(penStepsToGo); + penMotor.setSpeed( penSpeed ); + } +/* + while ( penMotor.distanceToGo() || rotMotor.distanceToGo() ) { + penMotor.runSpeedToPosition(); // Moving.... moving... moving.... + rotMotor.runSpeedToPosition(); + } + */ +} + +void setprgButtonState(){ + prgButtonState = 1; +} diff --git a/README.md b/README.md index d63ac11..a8ea736 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Eggduino Arduino Firmware for Eggbot / Spherebot with Inkscape-Integration -Version 1.4s +Version 1.6 tested with Inkscape Portable 0.91, Eggbot Extension and patched eggbot.py Regards: Eggduino-Firmware by Joachim Cerny, 2015 @@ -17,6 +17,7 @@ Features: - No collision-detection!! - Supported Servos: At least one type ;-) I use Arduino Servo-Lib with TG9e- standard servo. - Full Arduino-Compatible. I used an Arduino Uno +- Button-support (3 buttons) Tested and fully functional with Inkscape. diff --git a/VersionHistory.txt b/VersionHistory.txt index 7a4368a..8d08bd9 100644 --- a/VersionHistory.txt +++ b/VersionHistory.txt @@ -1,3 +1,10 @@ +05.05.2015 v1.6 +imported some improvements from user "bartebor" +fixed some timing issues +added button-support via #ifdefine +worked on penarm-shaking-bug +restructured some codesegments + 29.03.2015 v1.4 added prototype for PRG-Button support. somebody has to test it. Connect pushbutton between Pin2 und GND. disabled ccordinate transform for 16-microstepping, because Inkscape sends in 16-microstepping, as well. diff --git a/button.h b/button.h new file mode 100644 index 0000000..55bcf4c --- /dev/null +++ b/button.h @@ -0,0 +1,59 @@ +/* +* button.h +* +* Created: 04.05.2015 21:38:42 +* Author: Yogi +*/ + + +#ifndef __BUTTON_H__ +#define __BUTTON_H__ + +#include + +#define debounceDelay 50 + +typedef void (*ActionCb)(void); + +class Button +{ + +private: + long debounce; + byte state:1; + byte lastState:1; + byte pin; + ActionCb action; + Button( const Button &c ); + Button& operator=( const Button &c ); + +public: + + Button(byte p, ActionCb a): debounce(0), state(1), lastState(1), action(a), pin(p) {} ; + void check() { + byte b = digitalRead(pin); + long t = millis(); + + if (b != lastState) { + debounce = t; + } + + if ((t - debounce) > debounceDelay) { + if (b != state) { + state = b; + + if (!state) { + (*action)(); + } + } + } + + lastState = b; + }; + + + +}; //button + +#endif //__BUTTON_H__ +