diff --git a/MSerial.ino b/MSerial.cpp
similarity index 58%
rename from MSerial.ino
rename to MSerial.cpp
index bc2a489..3e16bf1 100644
--- a/MSerial.ino
+++ b/MSerial.cpp
@@ -1,8 +1,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
/*
@@ -29,22 +28,4 @@ void serial_setup(long baud) {
// serial receive interrupt
ISR(USART0_RX_vect) {
}
-*/
-
-
-/**
- * This file is part of makelangelo-firmware.
- *
- * makelangelo-firmware is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * makelangelo-firmware is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with makelangelo-firmware. If not, see .
- */
+*/
\ No newline at end of file
diff --git a/MServo.cpp b/MServo.cpp
index 23e24dd..c35952a 100644
--- a/MServo.cpp
+++ b/MServo.cpp
@@ -45,6 +45,8 @@
#include "MServo.h"
+#ifndef ESP8266
+
#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
@@ -333,3 +335,6 @@ bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive ;
}
+
+
+#endif // ESP8266
diff --git a/MServo.h b/MServo.h
index a24499d..2f233a7 100644
--- a/MServo.h
+++ b/MServo.h
@@ -45,6 +45,8 @@
#ifndef Servo_h
#define Servo_h
+#ifndef ESP8266
+
#include
#include
#include
@@ -86,10 +88,10 @@ typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
#else // everything else
-//#define _useTimer1
-#define _useTimer3
-//typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;
-typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
+#define _useTimer1
+//#define _useTimer3
+typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;
+//typedef enum { _timer3, _Nbr_16timers } timer16_Sequence_t ;
#endif
#define Servo_VERSION 2 // software version of this library
@@ -132,4 +134,6 @@ class Servo
int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH
};
-#endif
+#endif // ESP8266
+
+#endif // Servo_h
diff --git a/Makelangelo-firmware.ino b/Makelangelo-firmware.ino
index 8c3ff2c..9b5fd66 100644
--- a/Makelangelo-firmware.ino
+++ b/Makelangelo-firmware.ino
@@ -1,8 +1,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
@@ -10,7 +9,10 @@
// INCLUDES
//------------------------------------------------------------------------------
#include "configure.h"
-#include "lcd.h"
+#include "motor.h"
+#include "SD.h"
+#include "LCD.h"
+#include "eeprom.h"
#include // pkm fix for Arduino 1.5
@@ -48,6 +50,17 @@ long line_number = 0; // make sure commands arrive in order
float tool_offset[NUM_TOOLS][NUM_AXIES];
int current_tool = 0;
+#ifdef HAS_WIFI
+
+#include
+#include
+const char* SSID_NAME = WIFI_SSID_NAME;
+const char* SSID_PASS = WIFI_SSID_PASS;
+WiFiUDP port;
+unsigned int localPort = 9999;
+
+#endif // HAS_WIFI
+
@@ -56,6 +69,11 @@ int current_tool = 0;
//------------------------------------------------------------------------------
+void findStepDelay() {
+ step_delay = 1000000.0f / (DEFAULT_FEEDRATE / THREAD_PER_STEP);
+}
+
+
// returns angle of dy/dx as a value from 0...2PI
float atan3(float dy, float dx) {
float a = atan2(dy, dx);
@@ -65,8 +83,8 @@ float atan3(float dy, float dx) {
/**
- * @return switch state
- */
+ @return switch state
+*/
char readSwitches() {
#ifdef USE_LIMIT_SWITCH
// get the current switch state
@@ -77,13 +95,12 @@ char readSwitches() {
}
-/**
- * feed rate is given in units/min and converted to cm/s
- */
+/**
+ feed rate is given in units/min and converted to cm/s
+*/
void setFeedRate(float v1) {
if ( feed_rate != v1 ) {
feed_rate = v1;
- if (feed_rate > MAX_FEEDRATE) feed_rate = MAX_FEEDRATE;
if (feed_rate < MIN_FEEDRATE) feed_rate = MIN_FEEDRATE;
#ifdef VERBOSE
Serial.print(F("F="));
@@ -93,70 +110,55 @@ void setFeedRate(float v1) {
}
-void findStepDelay() {
- step_delay = 1000000.0f / DEFAULT_FEEDRATE;
-}
-
-
/**
- * @param delay in microseconds
- */
-void pause(long us) {
+ @param delay in microseconds
+*/
+void pause(const long us) {
delay(us / 1000);
delayMicroseconds(us % 1000);
}
/**
- * print the current feed rate
- */
-void printFeedRate() {
- Serial.print(F("F"));
- Serial.print(feed_rate);
- Serial.print(F("steps/s"));
-}
-
-
-/**
- * M101 Annn Tnnn Bnnn
- * Change axis A limits to max T and min B.
- * look for change to dimensions in command, apply and save changes.
- */
+ M101 Annn Tnnn Bnnn
+ Change axis A limits to max T and min B.
+ look for change to dimensions in command, apply and save changes.
+*/
void parseLimits() {
- int axisNumber = parseNumber('A',-1);
- if(axisNumber==-1) return;
- if(axisNumber>=NUM_AXIES) return;
-
+ int axisNumber = parseNumber('A', -1);
+ if (axisNumber == -1) return;
+ if (axisNumber >= NUM_AXIES) return;
+
float newT = parseNumber('T', axies[axisNumber].limitMax);
float newB = parseNumber('B', axies[axisNumber].limitMin);
- boolean changed=false;
-
- if(!equalEpsilon(axies[axisNumber].limitMax,newT)) {
- axies[axisNumber].limitMax=newT;
- changed=true;
+ boolean changed = false;
+
+ if (!equalEpsilon(axies[axisNumber].limitMax, newT)) {
+ axies[axisNumber].limitMax = newT;
+ changed = true;
}
- if(!equalEpsilon(axies[axisNumber].limitMin,newB)) {
- axies[axisNumber].limitMin=newB;
- changed=true;
+ if (!equalEpsilon(axies[axisNumber].limitMin, newB)) {
+ axies[axisNumber].limitMin = newB;
+ changed = true;
}
- if(changed==true) {
+ if (changed == true) {
saveLimits();
}
printConfig();
/*
- float pos[NUM_AXIES];
- int i;
- for(i=0;i180 degrees (PI radians)
- * @input cx center of circle x value
- * @input cy center of circle y value
- * @input destination point where movement ends
- * @input dir - ARC_CW or ARC_CCW to control direction of arc
- * @input new_feed_rate speed to travel along arc
- */
+ This method assumes the limits have already been checked.
+ This method assumes the start and end radius match.
+ This method assumes arcs are not >180 degrees (PI radians)
+ @input cx center of circle x value
+ @input cy center of circle y value
+ @input destination point where movement ends
+ @input dir - ARC_CW or ARC_CCW to control direction of arc
+ @input new_feed_rate speed to travel along arc
+*/
void arc(float cx, float cy, float *destination, char clockwise, float new_feed_rate) {
// get radius
float dx = axies[0].pos - cx;
@@ -284,7 +274,7 @@ void arc(float cx, float cy, float *destination, char clockwise, float new_feed_
float er = sqrt(dx * dx + dy * dy);
float da = ea - sa;
- if (clockwise != 0 && da < 0) ea += 2 * PI;
+ if (clockwise != 0 && da < 0) ea += 2 * PI;
else if (clockwise == 0 && da > 0) sa += 2 * PI;
da = ea - sa;
float dr = er - sr;
@@ -294,17 +284,17 @@ void arc(float cx, float cy, float *destination, char clockwise, float new_feed_
// float len=theta*circ/(PI*2.0);
// simplifies to
float len1 = abs(da) * sr;
- float len = sqrt( len1 * len1 + dr * dr );
+ float len = sqrt( len1 * len1 + dr * dr ); // mm
- int i, segments = ceil( len * SEGMENT_PER_CM_ARC );
+ int i, segments = ceil( len * SEGMENT_PER_CM_ARC / 10 );
- float n[NUM_AXIES], angle3, scale;
+ float n[NUM_AXIES], scale;
float a, r;
- #if NUM_AXIES>2
+#if NUM_AXIES>2
float sz = axies[2].pos;
float z = destination[2];
- #endif
-
+#endif
+
for (i = 0; i <= segments; ++i) {
// interpolate around the arc
scale = ((float)i) / ((float)segments);
@@ -314,9 +304,9 @@ void arc(float cx, float cy, float *destination, char clockwise, float new_feed_
n[0] = cx + cos(a) * r;
n[1] = cy + sin(a) * r;
- #if NUM_AXIES>2
+#if NUM_AXIES>2
n[2] = ( z - sz ) * scale + sz;
- #endif
+#endif
// send it to the planner
lineSafe(n, new_feed_rate);
}
@@ -324,26 +314,26 @@ void arc(float cx, float cy, float *destination, char clockwise, float new_feed_
/**
- * Instantly move the virtual plotter position. Does not check if the move is valid.
- */
+ Instantly move the virtual plotter position. Does not check if the move is valid.
+*/
void teleport(float *pos) {
wait_for_empty_segment_buffer();
int i;
- for(i=0;i= NUM_TOOLS) tool_id = NUM_TOOLS - 1;
current_tool = tool_id;
-#ifdef HAS_SD
- if (sd_printing_now) {
- sd_printing_paused = true;
- }
-#endif
}
/**
- * Look for character /code/ in the buffer and read the float that immediately follows it.
- * @return the value found. If nothing is found, /val/ is returned.
- * @input code the character to look for.
- * @input val the return value if /code/ is not found.
- */
+ Look for character /code/ in the buffer and read the float that immediately follows it.
+ @return the value found. If nothing is found, /val/ is returned.
+ @input code the character to look for.
+ @input val the return value if /code/ is not found.
+*/
float parseNumber(char code, float val) {
char *ptr = serialBuffer; // start at the beginning of buffer
while ((long)ptr > 1 && (*ptr) && (long)ptr < (long)serialBuffer + sofar) { // walk to the end
@@ -492,8 +487,8 @@ float parseNumber(char code, float val) {
/**
- * @return 1 if the character is found in the serial buffer, 0 if it is not found.
- */
+ @return 1 if the character is found in the serial buffer, 0 if it is not found.
+*/
char hasGCode(char code) {
char *ptr = serialBuffer; // start at the beginning of buffer
while ((long)ptr > 1 && (*ptr) && (long)ptr < (long)serialBuffer + sofar) { // walk to the end
@@ -506,9 +501,9 @@ char hasGCode(char code) {
}
/**
- * G4 [Snn] [Pnn]
- * Wait S milliseconds and P seconds.
- */
+ G4 [Snn] [Pnn]
+ Wait S milliseconds and P seconds.
+*/
void parseDwell() {
wait_for_empty_segment_buffer();
float delayTime = parseNumber('S', 0) + parseNumber('P', 0) * 1000.0f;
@@ -516,43 +511,47 @@ void parseDwell() {
}
-/**
- * G0-G1 [Xnnn] [Ynnn] [Znnn] [Unnn] [Vnnn] [Wnnn] [Ann] [Fnn]
- * straight lines
- */
+/**
+ G0-G1 [Xnnn] [Ynnn] [Znnn] [Unnn] [Vnnn] [Wnnn] [Ann] [Fnn]
+ straight lines. distance in mm.
+*/
void parseLine() {
float offset[NUM_AXIES];
get_end_plus_offset(offset);
- acceleration = min(max(parseNumber('A', acceleration), MIN_ACCELERATION), MAX_ACCELERATION);
+ acceleration = parseNumber('A', acceleration);
+ acceleration = min(max(acceleration, (float)MIN_ACCELERATION), (float)MAX_ACCELERATION);
float f = parseNumber('F', feed_rate);
-
+ f = max(f, (float)MIN_FEEDRATE);
+
int i;
float pos[NUM_AXIES];
- for(i=0;i=0;--i) {
- if(serialBuffer[i]=='*') {
+ for (i = strlen(serialBuffer) - 1; i >= 0; --i) {
+ if (serialBuffer[i] == '*') {
break;
}
}
-
- if(i>=0) {
+
+ if (i >= 0) {
// yes. is it valid?
char checksum = 0;
int c;
- for(c=0;c=strlen(serialBuffer)) {
- //Serial.println("No message.");
+ // wipe previous message
+ for (uint16_t j = LCD_MESSAGE_LENGTH / 2; j < LCD_MESSAGE_LENGTH; ++j) {
+ lcd_message[j] = ' ';
+ }
+
+ i += 4;
+ if (i >= strlen(serialBuffer)) {
// no message
- lcd_message[0]=0;
- lcd_message[LCD_WIDTH + 1]=0;
+ Serial.println("No message.");
return;
}
// preserve message for display
- int top = min(LCD_MESSAGE_LENGTH,MAX_BUF);
+ uint16_t top = min(LCD_MESSAGE_LENGTH, MAX_BUF);
- char *buf = serialBuffer+i;
- while(*buf==' ') ++buf; // eat whitespace
-
- //Serial.print("message found:");
- i=j=0;
- while(isPrintable(*buf) && *buf!='\r' && *buf!='\n' && i ")); // signal ready to receive input
@@ -1001,43 +1021,61 @@ void parser_ready() {
/**
- * reset all tool offsets
- */
+ reset all tool offsets
+*/
void tools_setup() {
for (int i = 0; i < NUM_TOOLS; ++i) {
for (int j = 0; j < NUM_AXIES; ++j) {
- tool_offset[i][j]=0;
+ tool_offset[i][j] = 0;
}
}
}
/**
- * runs once on machine start
- */
+ runs once on machine start
+*/
void setup() {
// start communications
Serial.begin(BAUD);
- SD_init();
- LCD_init();
+#ifdef HAS_WIFI
+ // Start WIFI
+ WiFi.mode(WIFI_AP);
+ Serial.println( WiFi.softAP(SSID_NAME, SSID_PASS) ? "WIFI OK":"WIFI FAILED" );
+ Serial.println( port.begin(localPort) ? "UDP OK" : "UDP FAILED" );
+ // Print the IP address
+ Serial.print("Use this URL to connect: http://");
+ Serial.print(WiFi.softAPIP());
+ Serial.print(':');
+ Serial.print(localPort);
+ Serial.println('/');
+#endif // HAS_WIFI
+
+ SD_setup();
+ LCD_setup();
loadConfig();
+ Serial.println("A1");
motor_setup();
+ Serial.println("A2");
motor_engage();
+ Serial.println("A3");
tools_setup();
+ Serial.println("A4");
findStepDelay();
+ Serial.println('B');
//easyPWM_init();
// initialize the plotter position.
float pos[NUM_AXIES];
- for(int i=0;i=3) pos[2]=PEN_UP_ANGLE;
+ if (NUM_AXIES >= 3) pos[2] = PEN_UP_ANGLE;
#endif
teleport(pos);
#ifdef MACHINE_HAS_LIFTABLE_PEN
@@ -1045,8 +1083,9 @@ void setup() {
#endif
setFeedRate(DEFAULT_FEEDRATE);
+ Serial.println('C');
robot_setup();
-
+
// display the help at startup.
help();
@@ -1055,8 +1094,8 @@ void setup() {
/**
- * See: http://www.marginallyclever.com/2011/10/controlling-your-arduino-through-the-serial-monitor/
- */
+ See: http://www.marginallyclever.com/2011/10/controlling-your-arduino-through-the-serial-monitor/
+*/
void Serial_listen() {
// listen for serial commands
while (Serial.available() > 0) {
@@ -1064,22 +1103,36 @@ void Serial_listen() {
if (c == '\r') continue;
if (sofar < MAX_BUF) serialBuffer[sofar++] = c;
if (c == '\n') {
- serialBuffer[sofar-1] = 0;
+ serialBuffer[sofar - 1] = 0;
// echo confirmation
- // Serial.println(F(serialBuffer));
+ //Serial.println(serialBuffer);
// do something with the command
processCommand();
parser_ready();
}
}
+
+#ifdef HAS_WIFI
+ int packetSize = port.parsePacket();
+ if (packetSize) {
+ int len = port.read(serialBuffer, MAX_BUF);
+ sofar = len;
+ if (len > 0) serialBuffer[len - 1] = 0;
+ Serial.println(serialBuffer);
+ processCommand();
+ port.beginPacket(port.remoteIP(), port.remotePort());
+ port.write("ok\r\n");
+ port.endPacket();
+ }
+#endif // HAS_WIFI
}
/**
- * main loop
- */
+ main loop
+*/
void loop() {
Serial_listen();
SD_check();
@@ -1093,39 +1146,21 @@ void loop() {
}
#if MACHINE_STYLE == ARM6
-/*
- static int switchState=LOW;
- if(digitalRead(MOTOR_5_LIMIT_SWITCH_PIN)!=switchState) {
- switchState = !switchState;
- Serial.println(switchState?"ON":"OFF");
- }
+ /*
+ static int switchState=LOW;
+ if(digitalRead(MOTOR_5_LIMIT_SWITCH_PIN)!=switchState) {
+ switchState = !switchState;
+ Serial.println(switchState?"ON":"OFF");
+ }
*/
/*
- Serial.print( digitalRead(MOTOR_0_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
- Serial.print( digitalRead(MOTOR_1_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
- Serial.print( digitalRead(MOTOR_2_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
- Serial.print( digitalRead(MOTOR_3_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
- Serial.print( digitalRead(MOTOR_4_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
- Serial.print( digitalRead(MOTOR_5_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
- Serial.println();*/
-
+ Serial.print( digitalRead(MOTOR_0_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
+ Serial.print( digitalRead(MOTOR_1_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
+ Serial.print( digitalRead(MOTOR_2_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
+ Serial.print( digitalRead(MOTOR_3_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
+ Serial.print( digitalRead(MOTOR_4_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
+ Serial.print( digitalRead(MOTOR_5_LIMIT_SWITCH_PIN)==HIGH ? "1 " : "0 ");
+ Serial.println();*/
+
#endif
}
-
-
-/**
- This file is part of makelangelo-firmware.
-
- makelangelo-firmware is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- makelangelo-firmware is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with DrawbotGUI. If not, see .
-*/
diff --git a/README.txt b/README.txt
index 7d275c0..9a758f7 100644
--- a/README.txt
+++ b/README.txt
@@ -14,6 +14,9 @@ Makelangelo-firmware can also support traditional XY gantries, CoreXY gantries,
Newer versions might be available at https://www.marginallyclever.com/product/makelangelo-firmware/
+## Note ##
+
+Unless otherwise stated in the code, the default units of measurement are millimeters (mm), kilograms (kg), and seconds (s).
## Instructions ##
- Make sure the parent folder is called Makelangelo-firmware.
@@ -24,7 +27,7 @@ Newer versions might be available at https://www.marginallyclever.com/product/ma
for Makelangelo 3 #define MACHINE_HARDWARE_VERSION 3
for Makelangelo 5 #define MACHINE_HARDWARE_VERSION 5
- Tools > board > set type for your flavor of arduino
-- Tools > port > set the connection for your arudion
+- Tools > port > set the connection for your arudio
- upload
For developers, please see
diff --git a/Vector3.h b/Vector3.h
index ce6a715..605c774 100644
--- a/Vector3.h
+++ b/Vector3.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
@@ -293,23 +292,4 @@ class Vector3 {
}
};
-
-
-/**
-* This file is part of makelangelo-firmware.
-*
-* makelangelo-firmware is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, either version 3 of the License, or
-* (at your option) any later version.
-*
-* makelangelo-firmware is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with makelangelo-firmware. If not, see .
-*/
-#endif
-
+#endif
\ No newline at end of file
diff --git a/board_mks.h b/board_mks.h
index 8f85c49..7a20ef8 100644
--- a/board_mks.h
+++ b/board_mks.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
// NOTE: MKS boards are identical to RAMPS boards, except that they have a few extra features.
diff --git a/board_ramps.h b/board_ramps.h
index c16ba95..96b7434 100644
--- a/board_ramps.h
+++ b/board_ramps.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
@@ -84,10 +83,15 @@
#define LCD_PINS_D6 27
#define LCD_PINS_D7 29
+// Encoder rotation values
+#define BTN_EN1 31
+#define BTN_EN2 33
+#define BTN_ENC 35
+
// SD card settings
-#define SDPOWER 31
-#define SDSS 33
-#define SDCARDDETECT 35
+#define SDPOWER -1
+#define SDSS 53
+#define SDCARDDETECT 49
#define KILL_PIN 41
#endif
diff --git a/board_rumba.h b/board_rumba.h
index 2804f8e..91965e6 100644
--- a/board_rumba.h
+++ b/board_rumba.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
diff --git a/board_sanguinolulu.h b/board_sanguinolulu.h
index 95388e0..6d963ea 100644
--- a/board_sanguinolulu.h
+++ b/board_sanguinolulu.h
@@ -1,32 +1,44 @@
-#ifndef BOARD_RAMPS_H
-#define BOARD_RAMPS_H
+#ifndef BOARD_SANGUINOLULU_H
+#define BOARD_SANGUINOLULU_H
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MOTHERBOARD == BOARD_SANGUINOLULU
-#define MAX_MOTORS (2)
-
+#define MAX_MOTORS (4)
+//x
#define MOTOR_0_DIR_PIN (21)
#define MOTOR_0_STEP_PIN (15)
#define MOTOR_0_ENABLE_PIN (14)
#define MOTOR_0_LIMIT_SWITCH_PIN (18)
-
+//y
#define MOTOR_1_DIR_PIN (23)
#define MOTOR_1_STEP_PIN (22)
#define MOTOR_1_ENABLE_PIN (14)
#define MOTOR_1_LIMIT_SWITCH_PIN (19)
-
-// TODO: if ZARPLOTTER & SANGUINOLULU throw a compile error, not enough motors.
+//z
+#define MOTOR_2_DIR_PIN (2)
+#define MOTOR_2_STEP_PIN (3)
+#define MOTOR_2_ENABLE_PIN (14)
+#define MOTOR_2_LIMIT_SWITCH_PIN (20)
+//e
+#define MOTOR_3_DIR_PIN (0)
+#define MOTOR_3_STEP_PIN (1)
+#define MOTOR_3_ENABLE_PIN (14)
+// the sanguinolulu doesn't have a limit switch pin for E.
+// I've assigned it to pin 24, the e-thermistor pin. I have no idea if this will work.
+#define MOTOR_3_LIMIT_SWITCH_PIN (24)
#define MAX_BOARD_SERVOS (1)
#define SERVO0_PIN (12)
-#endif
+#undef HAS_LCD
+#undef HAS_SD
+
+#endif
-#endif // BOARD_RAMPS_H
+#endif // BOARD_SANGUINOLULU_H
diff --git a/board_teensylu.h b/board_teensylu.h
index 082eaeb..0e6fe92 100644
--- a/board_teensylu.h
+++ b/board_teensylu.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
diff --git a/board_wemos.h b/board_wemos.h
new file mode 100644
index 0000000..a35c5a5
--- /dev/null
+++ b/board_wemos.h
@@ -0,0 +1,53 @@
+#ifndef BOARD_WEMOS_H
+#define BOARD_WEMOS_H
+//------------------------------------------------------------------------------
+// Makelangelo - firmware for various robot kinematic models
+// dan@marginallycelver.com 2013-12-26
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+//------------------------------------------------------------------------------
+
+// https://www.instructables.com/id/Programming-the-WeMos-Using-Arduino-SoftwareIDE/
+
+// cnc shield pins: https://blog.protoneer.co.nz/arduino-cnc-shield/arduino-cnc-shield-scematics-v3-xx/
+// WEMOS D1 R2 pins: https://protosupplies.com/wp-content/uploads/2018/07/Wemos-D1-Pin-Differences.pdf.jpg
+// WEMOS D1 R2 board type should be set to "LOLIN(WEMOS) R1 D2 & mini"
+
+#if MOTHERBOARD == BOARD_WEMOS
+
+// wrong board type set
+#ifndef ESP8266
+ #error "Oops! Make sure you have 'Wemos D1 R1' selected from the 'Tools -> Boards' menu."
+#endif
+
+// actual limit is 4 but I only have the pins for the first two motors.
+// TODO add more pin definitions
+#define MAX_MOTORS (2)
+
+#define MOTOR_0_DIR_PIN (3)
+#define MOTOR_0_STEP_PIN (0)
+#define MOTOR_0_ENABLE_PIN (6)
+#define MOTOR_0_LIMIT_SWITCH_PIN (7) /* X min */
+
+#define MOTOR_1_DIR_PIN (4)
+#define MOTOR_1_STEP_PIN (1)
+#define MOTOR_1_ENABLE_PIN (6)
+#define MOTOR_1_LIMIT_SWITCH_PIN (8) /* Y min */
+
+#define MAX_BOARD_SERVOS (1)
+#define SERVO0_PIN (14) /* Servo 1 */
+
+#define LIMIT_SWITCH_PIN_LEFT (MOTOR_0_LIMIT_SWITCH_PIN)
+#define LIMIT_SWITCH_PIN_RIGHT (MOTOR_1_LIMIT_SWITCH_PIN)
+
+#define HAS_WIFI
+#define WIFI_SSID_NAME "CSIS VAN #1" // WiFi AP SSID Name
+#define WIFI_SSID_PASS "TDPJYGZEDH123" // WiFi AP SSID Password
+
+#define CLOCK_FREQ (80000000L)
+
+#undef HAS_SD
+#undef HAS_LCD
+
+#endif // MOTHERBOARD == BOARD_WEMOS
+
+#endif // BOARD_WEMOS_H
diff --git a/configure.h b/configure.h
index 5a1e376..d7040be 100644
--- a/configure.h
+++ b/configure.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@@ -48,6 +47,17 @@
//#include "robot_arm5.h"
#include "robot_arm6.h"
+//------------------------------------------------------------------------------
+// LCD panels supported
+//------------------------------------------------------------------------------
+
+#define HAS_LCD // if you have an LCD panel
+#define HAS_SD // if you have SD card support on your LCD panel (must be on panel?)
+
+// only uncomment one of these options
+//#define LCD_IS_128X64 // reprapdiscount Full Graphic Smart LCD Controller
+#define LCD_IS_SMART // reprapdiscount Smart LCD Controller (including XXL model)
+
//------------------------------------------------------------------------------
// Microcontrollers supported
//------------------------------------------------------------------------------
@@ -56,6 +66,7 @@
#define BOARD_RAMPS 2
#define BOARD_SANGUINOLULU 3
#define BOARD_TEENSYLU 4
+#define BOARD_WEMOS 5
#define MOTHERBOARD BOARD_RUMBA // change this
@@ -63,14 +74,7 @@
#include "board_ramps.h"
#include "board_sanguinolulu.h"
#include "board_teensylu.h"
-
-//------------------------------------------------------------------------------
-// LCD panels supported
-//------------------------------------------------------------------------------
-
-// only uncomment one of these options
-#define LCD_IS_128X64 // reprapdiscount Full Graphic Smart LCD Controller
-//#define LCD_IS_SMART // reprapdiscount Smart LCD Controller (including XXL model)
+#include "board_wemos.h"
//------------------------------------------------------------------------------
// MOTOR DETAILS
@@ -109,7 +113,10 @@
#define MAX_BUF (64) // What is the longest message Arduino can store?
// buffering commands
+#ifndef MAX_SEGMENTS
#define MAX_SEGMENTS (32) // number of line segments to buffer ahead. must be a power of two.
+#endif
+
#define SEGMOD(x) ((x)&(MAX_SEGMENTS-1))
//------------------------------------------------------------------------------
@@ -136,11 +143,10 @@
//#error "NUM_SERVOS + NUM_MOTORS != NUM_AXIES"
#endif
-
//------------------------------------------------------------------------------
// EEPROM MEMORY MAP
//------------------------------------------------------------------------------
-#define EEPROM_VERSION 8 // Increment when adding new variables
+#define FIRMWARE_VERSION 9 // Increment when adding new variables
#define ADDR_VERSION 0 // 0..255 (1 byte)
#define ADDR_UUID (ADDR_VERSION+1) // long - 4 bytes
#define ADDR_LIMITS (ADDR_UUID+4) // float - 4 bytes
@@ -154,21 +160,38 @@
//------------------------------------------------------------------------------
// TIMERS
//------------------------------------------------------------------------------
-// for timer interrupt control
-#define CLOCK_FREQ (16000000L)
-#define MAX_COUNTER (65536L)
-// time passed with no instruction? Make sure PC knows we are waiting.
-#define TIMEOUT_OK (1000)
+
+#ifdef ESP8266
+
+ #define CLOCK_FREQ (80000000L)
+ #define MAX_COUNTER (4294967295L) // 32 bits
+ #define CRITICAL_SECTION_START noInterrupts();
+ #define CRITICAL_SECTION_END interrupts();
+
+#else // ESP8266
+
+ // for timer interrupt control
+ #define CLOCK_FREQ (16000000L)
+ #define MAX_COUNTER (65536L) // 16 bits
+ #ifndef CRITICAL_SECTION_START
+ #define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli();
+ #define CRITICAL_SECTION_END SREG = _sreg;
+ #endif //CRITICAL_SECTION_START
+
+#endif // ESP8266
+
+#define TIMER_RATE ((CLOCK_FREQ)/8)
// optimize code, please
#define FORCE_INLINE __attribute__((always_inline)) inline
+// TODO a guess. use real math here!
+// https://reprap.org/wiki/Step_rates
+// 0.9deg stepper, 20-tooth GT2 pulley, 1/16 microstepping = 160 steps/mm, 1500mm/s = 240000 steps/s
+#define CLOCK_MAX_STEP_FREQUENCY (240000)
+#define CLOCK_MIN_STEP_FREQUENCY (CLOCK_FREQ/500000U)
-#ifndef CRITICAL_SECTION_START
- #define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli();
- #define CRITICAL_SECTION_END SREG = _sreg;
-#endif //CRITICAL_SECTION_START
-
+#define TIMEOUT_OK (1000)
//------------------------------------------------------------------------------
// STRUCTURES
@@ -182,53 +205,35 @@ typedef struct {
} Axis;
-// for line()
-typedef struct {
- long step_count;
- long delta; // number of steps to move
- long absdelta;
- int dir;
- float delta_normalized;
-} SegmentAxis;
-
-
-typedef struct {
- int step_pin;
- int dir_pin;
- int enable_pin;
- int limit_switch_pin;
-} Motor;
-
-
-typedef struct {
- SegmentAxis a[NUM_MOTORS+NUM_SERVOS];
- int steps_total;
- int steps_taken;
- int accel_until;
- int decel_after;
- unsigned short feed_rate_max;
- unsigned short feed_rate_start;
- unsigned short feed_rate_start_max;
- unsigned short feed_rate_end;
- char nominal_length_flag;
- char recalculate_flag;
- char busy;
-} Segment;
-
+#include "motor.h"
//------------------------------------------------------------------------------
// GLOBALS
//------------------------------------------------------------------------------
-extern Segment line_segments[MAX_SEGMENTS];
-extern Segment *working_seg;
-extern volatile int current_segment;
-extern volatile int last_segment;
+extern float feed_rate;
extern float acceleration;
-extern Motor motors[NUM_MOTORS+NUM_SERVOS];
-extern const char *AxisNames;
-extern const char *MotorNames;
-extern float maxFeedRate[NUM_MOTORS];
-
+extern float step_delay;
+extern int robot_uid;
+extern Axis axies[NUM_AXIES];
+extern float calibrateRight;
+extern float calibrateLeft;
+extern char serialBuffer[MAX_BUF + 1]; // Serial buffer
+extern int sofar; // Serial buffer progress
+
+extern void pause(const long us);
+extern void findStepDelay();
+extern void IK(const float *const axies, long *motorStepArray);
+extern int FK(long *motorStepArray,float *axies);
+extern void robot_findHome();
+extern void robot_setup();
+extern void processCommand();
+extern void parser_ready();
+extern void teleport(float *pos);
+extern void lineSafe(float *pos, float new_feed_rate);
+extern void get_end_plus_offset(float *results);
+extern void set_tool_offset(int toolID, float *pos);
+extern void reportCalibration();
+extern void where();
#endif // CONFIGURE_H
diff --git a/eeprom.ino b/eeprom.cpp
similarity index 74%
rename from eeprom.ino
rename to eeprom.cpp
index 6fde590..3fb9282 100644
--- a/eeprom.ino
+++ b/eeprom.cpp
@@ -1,23 +1,23 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// INCLUDES
//------------------------------------------------------------------------------
+#include "configure.h"
+#include "motor.h"
#include
#include // for type definitions
-
/**
* from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1234477290/3
*/
void EEPROM_writeLong(int ee, long value) {
byte* p = (byte*)(void*)&value;
- for (int i = 0; i < sizeof(value); i++)
+ for (uint16_t i = 0; i < sizeof(value); i++)
EEPROM.write(ee++, *p++);
}
@@ -28,7 +28,7 @@ void EEPROM_writeLong(int ee, long value) {
float EEPROM_readLong(int ee) {
long value = 0;
byte* p = (byte*)(void*)&value;
- for (int i = 0; i < sizeof(value); i++)
+ for (uint16_t i = 0; i < sizeof(value); i++)
*p++ = EEPROM.read(ee++);
return value;
}
@@ -84,7 +84,7 @@ void loadLimits() {
* @param limits NUM_AXIES pairs of floats. each pair is one float for max limit and one for min limit.
*/
void adjustDimensions(float *limits) {
- int i,j;
+ int i,j=0;
int changed=0;
float v;
for(i=0;i.
- */
diff --git a/eeprom.h b/eeprom.h
new file mode 100644
index 0000000..332f99e
--- /dev/null
+++ b/eeprom.h
@@ -0,0 +1,59 @@
+#ifndef EEPROM_H
+#define EEPROM_H
+//------------------------------------------------------------------------------
+// Makelangelo - firmware for various robot kinematic models
+// dan@marginallycelver.com 2013-12-26
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+//------------------------------------------------------------------------------
+
+/**
+ *
+ */
+char loadVersion();
+
+/**
+ *
+ */
+void saveUID();
+
+/**
+ *
+ */
+void saveLimits();
+
+/**
+ *
+ */
+void loadLimits();
+
+/**
+ * @param limits NUM_AXIES pairs of floats. each pair is one float for max limit and one for min limit.
+ */
+void adjustDimensions(float *limits);
+
+/**
+ *
+ */
+void saveHome();
+
+/**
+ *
+ */
+void loadHome();
+
+/**
+ *
+ */
+void saveCalibration();
+
+/**
+ *
+ */
+void loadCalibration();
+
+/**
+ *
+ */
+void loadConfig();
+
+#endif // EEPROM_H
\ No newline at end of file
diff --git a/lcd.cpp b/lcd.cpp
new file mode 100644
index 0000000..7f9bf4e
--- /dev/null
+++ b/lcd.cpp
@@ -0,0 +1,881 @@
+//------------------------------------------------------------------------------
+// Makelangelo - firmware for various robot kinematic models
+// dan@marginallycelver.com 2013-12-26
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// INCLUDES
+//------------------------------------------------------------------------------
+#include "configure.h"
+#include "lcd.h"
+#include "sdcard.h"
+
+
+#ifdef HAS_LCD
+
+#ifdef LCD_IS_SMART
+#include
+#endif
+#ifdef LCD_IS_128X64
+#include
+#include
+#include
+#include
+#include "dogm_font_data_6x9.h"
+#endif
+
+//------------------------------------------------------------------------------
+// GLOBALS
+//------------------------------------------------------------------------------
+#ifdef LCD_IS_SMART
+LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7);
+#endif
+#ifdef LCD_IS_128X64
+// This is not ideal - will not work when board models change.
+U8GLIB_ST7920_128X64_1X u8g(LCD_PINS_D4, LCD_PINS_ENABLE, LCD_PINS_RS);
+#endif
+
+uint32_t lcd_draw_delay = 0;
+
+int lcd_rot_old = 0;
+int lcd_turn = 0;
+int lcd_posx = 0, lcd_posy = 0;
+char lcd_click_old = HIGH;
+char lcd_click_now = false;
+uint8_t speed_adjust = 100;
+char lcd_message[LCD_MESSAGE_LENGTH + 1];
+char lcd_dirty=0;
+
+int menu_position_sum = 0, menu_position = 0, screen_position = 0, num_menu_items = 0, ty, screen_end;
+
+
+void (*current_menu)();
+
+
+#ifdef LCD_IS_128X64
+/**
+ Made with Marlin Bitmap Converter
+ http://marlinfw.org/tools/u8glib/converter.html
+
+ This bitmap from the file 'icon_mono.png'
+ Filesize: 906 Bytes
+ Size bitmap: 108 bytes
+*/
+#define logoImageWidth 32
+#define logoImageHeight 32
+
+const unsigned char logoImage [] PROGMEM = {
+ 0x00, 0x60, 0x00, 0x00, // .........##.....................
+ 0x00, 0xF0, 0x00, 0x00, // ........####....................
+ 0x03, 0x10, 0x00, 0x00, // ......##...#....................
+ 0x01, 0x60, 0x00, 0x00, // .......#.##.....................
+ 0x01, 0xC0, 0x00, 0x00, // .......###......................
+ 0x00, 0x9F, 0xF0, 0x00, // ........#..#########............
+ 0x00, 0xF0, 0x3C, 0x00, // ........####......####..........
+ 0x01, 0xC0, 0x3F, 0x00, // .......###........######........
+ 0x03, 0x00, 0x1F, 0x80, // ......##...........######.......
+ 0x06, 0x00, 0x1F, 0xC0, // .....##............#######......
+ 0x0C, 0x02, 0x0F, 0xE0, // ....##........#.....#######.....
+ 0x08, 0x06, 0x0F, 0xE0, // ....#........##.....#######.....
+ 0x18, 0x02, 0x0F, 0xF0, // ...##.........#.....########....
+ 0x10, 0x02, 0x0F, 0xF0, // ...#..........#.....########....
+ 0x31, 0x80, 0x07, 0xF0, // ..##...##............#######....
+ 0x23, 0x80, 0x07, 0xF8, // ..#...###............########...
+ 0x23, 0x00, 0x07, 0xF8, // ..#...##.............########...
+ 0x23, 0x00, 0x07, 0xF8, // ..#...##.............########...
+ 0x23, 0x00, 0x07, 0xF8, // ..#...##.............########...
+ 0x21, 0x80, 0x07, 0xF8, // ..#....##............########...
+ 0x20, 0x00, 0x07, 0xF8, // ..#..................########...
+ 0x30, 0x00, 0x37, 0xF8, // ..##..............##.########...
+ 0x30, 0x00, 0x63, 0xF0, // ..##.............##...######....
+ 0x10, 0x00, 0x63, 0xF0, // ...#.............##...######....
+ 0x18, 0x00, 0x63, 0xF0, // ...##............##...######....
+ 0x08, 0x60, 0x37, 0xE0, // ....#....##.......##.######.....
+ 0x04, 0x20, 0x0F, 0xC0, // .....#....#.........######......
+ 0x06, 0x00, 0x1F, 0xC0, // .....##............#######......
+ 0x03, 0x00, 0x1F, 0x80, // ......##...........######.......
+ 0x00, 0xC0, 0x3E, 0x00, // ........##........#####.........
+ 0x00, 0x70, 0x3C, 0x00, // .........###......####..........
+ 0x00, 0x1F, 0xE0, 0x00 // ...........########.............
+};
+#endif
+
+//------------------------------------------------------------------------------
+// MACROS
+//------------------------------------------------------------------------------
+
+/**
+ Clear the screen
+*/
+#ifdef LCD_IS_SMART
+inline void LCD_clear() {
+ for (int i = 0; i < LCD_MESSAGE_LENGTH; ++i) lcd_message[i] = ' ';
+ lcd_message[LCD_MESSAGE_LENGTH - 1] = 0;
+}
+#endif
+#ifdef LCD_IS_128X64
+inline void LCD_clear() {
+ //u8g.firstPage();
+ //while( u8g.nextPage() );
+ u8g.setColorIndex(0);
+ u8g.drawBox(0, 0, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT);
+ u8g.setColorIndex(1);
+}
+#endif
+
+/**
+ print text to the LCD
+*/
+#ifdef LCD_IS_SMART
+inline void LCD_advance() {
+ lcd_posx++;
+ if (lcd_posx >= LCD_WIDTH) {
+ lcd_posx = 0;
+ lcd_posy++;
+ if (lcd_posy >= LCD_HEIGHT) {
+ lcd_posy = 0;
+ }
+ }
+}
+
+inline void LCD_print(const char *x) {
+ while ((*x) != 0) {
+ lcd_message[lcd_posy * LCD_WIDTH + lcd_posx] = *x;
+ x++;
+ LCD_advance();
+ }
+}
+
+//inline void LCD_print(const __FlashStringHelper *x) {
+// LCD_print((const PROGMEM char*)x);
+//}
+
+// see https://en.wikibooks.org/wiki/C_Programming/stdlib.h/itoa
+inline void LCD_print(long x) {
+ char b[12];
+ itoa(x, b, 10);
+ LCD_print(b);
+}
+
+inline void LCD_print(int x) {
+ char b[12];
+ itoa(x, b, 10);
+ LCD_print(b);
+}
+
+inline void LCD_print(const char x) {
+ lcd_message[lcd_posy * LCD_WIDTH + lcd_posx] = x;
+ LCD_advance();
+}
+#endif
+#ifdef LCD_IS_128X64
+#define LCD_print u8g.print
+#endif
+
+
+/**
+ Set the row/column of text at which to begin printing
+*/
+#ifdef LCD_IS_SMART
+#define LCD_setCursor(x,y) {lcd_posx=x; lcd_posy=y;}
+#endif
+#ifdef LCD_IS_128X64
+#define LCD_setCursor(x,y) u8g.setPrintPos(((x)+1)*FONT_WIDTH,((y)+1)*FONT_HEIGHT)
+#endif
+
+
+
+// Convenience macros that make it easier to generate menus
+
+#define MENU_START \
+ ty=0;
+
+#define MENU_END \
+ num_menu_items=ty; \
+
+#define MENU_ITEM_START(key) \
+ if(ty>=screen_position && ty':' '); \
+ LCD_print(key); \
+
+#define MENU_ITEM_END() \
+ } \
+ ++ty;
+
+#define MENU_GOTO(new_menu) { \
+ lcd_click_now=false; \
+ LCD_clear(); \
+ num_menu_items=screen_position=menu_position=menu_position_sum=0; \
+ screen_end = screen_position + LCD_HEIGHT; \
+ current_menu=new_menu; \
+ return; \
+ }
+
+#define MENU_LABEL(menu_label) \
+ MENU_ITEM_START(menu_label) \
+ MENU_ITEM_END()
+
+#define MENU_SUBMENU(menu_label,menu_method) \
+ MENU_ITEM_START(menu_label) \
+ if(menu_position==ty && lcd_click_now) MENU_GOTO(menu_method); \
+ MENU_ITEM_END()
+
+#define MENU_ACTION(menu_label,menu_method) MENU_SUBMENU(menu_label,menu_method)
+
+#define MENU_LONG(key,value) \
+ MENU_ITEM_START(key) \
+ LCD_print_long(value); \
+ if(menu_position==ty && lcd_click_now) LCD_update_long(key,value); \
+ MENU_ITEM_END()
+
+#define MENU_FLOAT(key,value) \
+ MENU_ITEM_START(key) \
+ LCD_print_float(value); \
+ if(menu_position==ty && lcd_click_now) LCD_update_float(key,value); \
+ MENU_ITEM_END()
+
+
+//------------------------------------------------------------------------------
+// METHODS
+//------------------------------------------------------------------------------
+
+void LCD_status_menu();
+void LCD_main_menu();
+void LCD_drawSplash();
+void LCD_driveX();
+void LCD_driveY();
+void LCD_driveZ();
+void LCD_driveF();
+void LCD_print_float(float);
+void LCD_print_long(long);
+void LCD_refresh_display();
+void LCD_draw_border();
+
+
+void LCD_read() {
+ // detect potentiometer changes
+ int rot = ((digitalRead(BTN_EN1) == LOW) << BLEN_A)
+ | ((digitalRead(BTN_EN2) == LOW) << BLEN_B);
+ // potentiometer uses grey code. Pattern is 0 3
+ if (lcd_rot_old != rot) {
+ switch (rot) {
+ case ENCROT0:
+ if ( lcd_rot_old == ENCROT3 ) lcd_turn++;
+ else if ( lcd_rot_old == ENCROT1 ) lcd_turn--;
+ break;
+ case ENCROT1:
+ if ( lcd_rot_old == ENCROT0 ) lcd_turn++;
+ else if ( lcd_rot_old == ENCROT2 ) lcd_turn--;
+ break;
+ case ENCROT2:
+ if ( lcd_rot_old == ENCROT1 ) lcd_turn++;
+ else if ( lcd_rot_old == ENCROT3 ) lcd_turn--;
+ break;
+ case ENCROT3:
+ if ( lcd_rot_old == ENCROT2 ) lcd_turn++;
+ else if ( lcd_rot_old == ENCROT0 ) lcd_turn--;
+ break;
+ }
+ //if(lcd_turn !=0) Serial.print(lcd_turn>0?'+':'-'); // for debugging potentiometer
+ //else Serial.print(' ');
+ //Serial.println(lcd_turn); // for debugging potentiometer
+ }
+ //Serial.println(rot); // for debugging potentiometer
+
+ lcd_rot_old = rot;
+
+
+ // find click state
+ int btn = digitalRead(BTN_ENC);
+ if ( btn != lcd_click_old && btn == HIGH ) {
+ lcd_click_now = true;
+ }
+ lcd_click_old = btn;
+}
+
+
+void LCD_pause() {
+ // TODO: if pen down before pause, lift pen on pause, lower pen on unpause.
+ // problem: machine does not know what is pen up or down.
+#ifdef HAS_SD
+ sd_printing_paused = (sd_printing_paused == true ? false : true);
+#endif
+ MENU_GOTO(LCD_main_menu);
+}
+
+
+void LCD_stop() {
+#ifdef HAS_SD
+ sd_printing_now = false;
+#endif
+ MENU_GOTO(LCD_main_menu);
+}
+
+void LCD_disable_motors() {
+ motor_disengage();
+ MENU_GOTO(LCD_main_menu);
+}
+
+void LCD_enable_motors() {
+ motor_engage();
+ MENU_GOTO(LCD_main_menu);
+}
+
+
+void LCD_find_home() {
+ robot_findHome();
+ MENU_GOTO(LCD_main_menu);
+}
+
+
+void LCD_this_is_home() {
+ float offset[NUM_AXIES];
+ for (int i = 0; i < NUM_AXIES; ++i) offset[i] = axies[i].homePos;
+ teleport(offset);
+ MENU_GOTO(LCD_main_menu);
+}
+
+
+void LCD_go_home() {
+ float homes[NUM_AXIES];
+ for (int i = 0; i < NUM_AXIES; ++i) homes[i] = axies[i].homePos;
+ lineSafe( homes, DEFAULT_FEEDRATE );
+ MENU_GOTO(LCD_main_menu);
+}
+
+
+void LCD_drive_menu() {
+ MENU_START
+ MENU_SUBMENU("Back", LCD_main_menu);
+ MENU_ACTION("Disable motors", LCD_disable_motors);
+ MENU_ACTION("Enable motors", LCD_enable_motors);
+ MENU_SUBMENU("X", LCD_driveX);
+ MENU_SUBMENU("Y", LCD_driveY);
+ MENU_SUBMENU("Z", LCD_driveZ);
+ MENU_SUBMENU("Feedrate", LCD_driveF);
+ MENU_END
+}
+
+
+void LCD_driveX() {
+ if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
+
+ float offset[NUM_AXIES];
+ get_end_plus_offset(offset);
+
+ if (lcd_turn) {
+ offset[0] += lcd_turn > 0 ? 1 : -1;
+ lineSafe(offset, feed_rate);
+ }
+
+ LCD_setCursor( 0, 0);
+ LCD_print('X');
+ LCD_print_float(offset[0]);
+}
+
+
+void LCD_driveY() {
+ if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
+
+ float offset[NUM_AXIES];
+ get_end_plus_offset(offset);
+
+ if (lcd_turn) {
+ offset[1] += lcd_turn > 0 ? 1 : -1;
+ lineSafe(offset, feed_rate);
+ }
+
+ LCD_setCursor( 0, 0);
+ LCD_print('Y');
+ LCD_print_float(offset[1]);
+}
+
+
+void LCD_driveZ() {
+ if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
+
+ float offset[NUM_AXIES];
+ get_end_plus_offset(offset);
+
+ if (lcd_turn) {
+ // protect servo, don't drive beyond physical limits
+ offset[2] += lcd_turn > 0 ? 1 : -1;
+ lineSafe(offset, feed_rate);
+ }
+
+ LCD_setCursor( 0, 0);
+ LCD_print('Z');
+ LCD_print_float(offset[2]);
+}
+
+
+void LCD_driveF() {
+ if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
+
+ if (lcd_turn) {
+ // protect servo, don't drive beyond physical limits
+ float newF = feed_rate + lcd_turn > 0 ? 1 : -1;
+ if (newF < MIN_FEEDRATE) newF = MIN_FEEDRATE;
+ if (newF > MAX_FEEDRATE) newF = MAX_FEEDRATE;
+ // move
+ feed_rate = newF;
+ }
+
+ LCD_setCursor( 0, 0);
+ LCD_print('F');
+ LCD_print_float(feed_rate);
+}
+
+
+void LCD_start_menu() {
+#ifdef HAS_SD
+ if (!sd_inserted) MENU_GOTO(LCD_main_menu);
+
+ /*
+ Serial.print(menu_position ); Serial.print("\t"); // 0
+ Serial.print(menu_position_sum); Serial.print("\t"); // 1
+ Serial.print(screen_position ); Serial.print("\t"); // 0
+ Serial.print(num_menu_items ); Serial.print("\n"); // 8
+ */
+ if(lcd_turn!=0 || lcd_click_now==1) lcd_dirty=1;
+
+ if(lcd_dirty==1) {
+ //long t0=micros();
+
+ MENU_START
+ MENU_SUBMENU("Back", LCD_main_menu);
+
+ root.rewindDirectory();
+ while ( true ) {
+ //long tStart = millis();
+ File entry = root.openNextFile();
+ //long tEnd = millis();
+ //Serial.print(tEnd-tStart);
+ //Serial.print('\t');
+ if (!entry) {
+ // no more files, return to the first file in the directory
+ break;
+ }
+ const char *filename = entry.name();
+ //Serial.print( entry.isDirectory()?">":" " );
+ //Serial.println(filename);
+ if (!entry.isDirectory() && filename[0] != '_') {
+ MENU_ITEM_START(filename)
+ if (menu_position == ty && lcd_click_now) {
+ lcd_click_now = false;
+ SD_StartPrintingFile(filename);
+ MENU_GOTO(LCD_status_menu);
+ }
+ MENU_ITEM_END()
+ }
+ entry.close();
+ }
+ MENU_END
+
+ //long t1=micros();
+ //Serial.print(menu_position,DEC);
+ //Serial.print(' ');
+ //Serial.print(num_menu_items,DEC);
+ //Serial.print(' ');
+ //Serial.print(t1-t0);
+ //Serial.println();
+ lcd_dirty=0;
+ }
+
+#else
+ // i don't know how you got here surfing the LCD panel.
+ // someone messed up in the logic. Go back to the main menu.
+ MENU_GOTO(LCD_main_menu);
+#endif
+}
+
+
+void draw_border(int width, int height, int landscape) {
+#if NUM_AXIES == 3
+ LCD_clear();
+ LCD_setCursor(0, 0);
+ LCD_print("Drawing border...");
+
+ width /= 2;
+ height /= 2;
+
+ if (landscape == 1) {
+ // swap the two values.
+ int temp = width;
+ width = height;
+ height = temp;
+ }
+
+ // get start position
+ float start[NUM_AXIES];
+ get_end_plus_offset(start);
+
+ float pos[NUM_AXIES];
+ // lift pen at current position
+ pos[0] = start[0];
+ pos[1] = start[1];
+ pos[2] = PEN_UP_ANGLE;
+ lineSafe( pos, feed_rate );
+ // move to first corner
+ pos[0] = -width; pos[1] = height; lineSafe( pos, feed_rate );
+ // lower pen
+ pos[2] = PEN_DOWN_ANGLE;
+ lineSafe( pos, feed_rate );
+ // move around border
+ pos[0] = width; pos[1] = height; lineSafe( pos, feed_rate );
+ pos[0] = width; pos[1] = -height; lineSafe( pos, feed_rate );
+ pos[0] = -width; pos[1] = -height; lineSafe( pos, feed_rate );
+ pos[0] = -width; pos[1] = height; lineSafe( pos, feed_rate );
+ // lift pen
+ pos[2] = PEN_UP_ANGLE; lineSafe( pos, feed_rate );
+
+ // return to start position
+ lineSafe( start, feed_rate );
+#endif // NUM_AXIES
+ MENU_GOTO(LCD_draw_border);
+}
+
+void draw_A2_portrait() {
+ draw_border(420, 594, 0);
+}
+void draw_A3_portrait() {
+ draw_border(297, 420, 0);
+}
+void draw_A4_portrait() {
+ draw_border(210, 297, 0);
+}
+void draw_A5_portrait() {
+ draw_border(148, 210, 0);
+}
+void draw_USletter_portrait() {
+ draw_border(216, 279, 0);
+}
+void draw_USlegal_portrait() {
+ draw_border(216, 356, 0);
+}
+
+void draw_A2_landscape() {
+ draw_border(420, 594, 1);
+}
+void draw_A3_landscape() {
+ draw_border(297, 420, 1);
+}
+void draw_A4_landscape() {
+ draw_border(210, 297, 1);
+}
+void draw_A5_landscape() {
+ draw_border(148, 210, 1);
+}
+void draw_USletter_landscape() {
+ draw_border(216, 279, 1);
+}
+void draw_USlegal_landscape() {
+ draw_border(216, 356, 1);
+}
+
+void LCD_draw_border() {
+ MENU_START
+ MENU_SUBMENU("Back", LCD_main_menu);
+ MENU_ACTION("A2 portrait", draw_A2_portrait);
+ MENU_ACTION("A3 portrait", draw_A3_portrait);
+ MENU_ACTION("A4 portrait", draw_A4_portrait);
+ MENU_ACTION("A5 portrait", draw_A5_portrait);
+ MENU_ACTION("US legal portrait", draw_USlegal_portrait);
+ MENU_ACTION("US letter portrait", draw_USletter_portrait);
+
+ MENU_ACTION("A2 landscape", draw_A2_landscape);
+ MENU_ACTION("A3 landscape", draw_A3_landscape);
+ MENU_ACTION("A4 landscape", draw_A4_landscape);
+ MENU_ACTION("A5 landscape", draw_A5_landscape);
+ MENU_ACTION("US legal landscape", draw_USlegal_landscape);
+ MENU_ACTION("US letter landscape", draw_USletter_landscape);
+ MENU_END
+}
+
+
+void LCD_update_long(char *label, long &value) {
+ LCD_clear();
+ do {
+ LCD_read();
+ if ( lcd_turn ) {
+ value += lcd_turn > 0 ? 1 : -1;
+ lcd_turn = 0;
+ }
+ LCD_setCursor(0, 0);
+ LCD_print(label);
+ LCD_setCursor(0, 1);
+ LCD_print_long(value);
+ } while ( !lcd_click_now );
+}
+
+
+void LCD_update_float(char *label, float &value, float stepSize = 0.01) {
+ LCD_clear();
+ do {
+ LCD_read();
+ if ( lcd_turn ) {
+ value += lcd_turn > 0 ? stepSize : -stepSize;
+ lcd_turn = 0;
+ }
+ LCD_setCursor(0, 0);
+ LCD_print(label);
+ LCD_setCursor(0, 1);
+ LCD_print_float(value);
+ } while ( !lcd_click_now );
+}
+
+
+void LCD_print_long(long v) {
+ long av = abs(v);
+ int x = 1000;
+ while (x > av && x > 1) {
+ LCD_print(' ');
+ x /= 10;
+ };
+ if (v > 0) LCD_print(' ');
+ LCD_print(v);
+}
+
+
+
+void LCD_print_float(float v) {
+ int left = abs(v);
+ int right = abs((int)(v * 100) % 100);
+
+ if (left < 1000) LCD_print(' ');
+ if (left < 100) LCD_print(' ');
+ if (left < 10) LCD_print(' ');
+
+ LCD_print(left);
+ LCD_print('.');
+ LCD_print(right);
+}
+#endif // HAS_LCD
+
+
+
+
+void LCD_update() {
+#ifdef HAS_LCD
+ LCD_read();
+
+ if (millis() >= lcd_draw_delay ) {
+ lcd_draw_delay = millis() + LCD_DRAW_DELAY;
+
+ //Serial.print(lcd_turn,DEC);
+ //Serial.print('\t'); Serial.print(menu_position,DEC);
+ //Serial.print('\t'); Serial.print(menu_position_sum,DEC);
+ //Serial.print('\t'); Serial.print(screen_position,DEC);
+ //Serial.print('\t'); Serial.print(screen_end,DEC);
+ //Serial.print('\t'); Serial.print(num_menu_items,DEC);
+ //Serial.print('\n');
+
+ // update the menu position
+ if ( lcd_turn && num_menu_items > 1 ) {
+ int originalPosition = menu_position_sum / LCD_TURN_PER_MENU;
+ menu_position_sum += lcd_turn;
+
+ menu_position = menu_position_sum / LCD_TURN_PER_MENU;
+ if (menu_position > num_menu_items - 1) menu_position = num_menu_items - 1;
+ if (menu_position < 0) menu_position = 0;
+
+ if (originalPosition != menu_position) {
+ LCD_clear();
+ }
+
+ //Serial.println(menu_position);
+
+ if (screen_position > menu_position) screen_position = menu_position;
+ if (screen_position < menu_position - (LCD_HEIGHT - 1)) screen_position = menu_position - (LCD_HEIGHT - 1);
+ screen_end = screen_position + LCD_HEIGHT;
+ }
+
+ // draw the new screen contents
+ #ifdef LCD_IS_128X64
+ u8g.firstPage();
+ do {
+ #endif
+ (*current_menu)();
+ #ifdef LCD_IS_128X64
+ } while(u8g.nextPage());
+ #endif
+
+ lcd_turn = 0; // reset. must come after (*current_menu)() because it might be used there. (damn globals...)
+ }
+ LCD_refresh_display();
+#endif // HAS_LCD
+}
+
+
+void LCD_refresh_display() {
+#ifdef HAS_LCD
+#ifdef LCD_IS_SMART
+ char temp[LCD_MESSAGE_LENGTH];
+ memcpy(temp + (LCD_WIDTH * 0), lcd_message + (LCD_WIDTH * 0), LCD_WIDTH);
+ memcpy(temp + (LCD_WIDTH * 1), lcd_message + (LCD_WIDTH * 2), LCD_WIDTH);
+ memcpy(temp + (LCD_WIDTH * 2), lcd_message + (LCD_WIDTH * 1), LCD_WIDTH);
+ memcpy(temp + (LCD_WIDTH * 3), lcd_message + (LCD_WIDTH * 3), LCD_WIDTH);
+ for (int i = 0; i < LCD_MESSAGE_LENGTH-1; ++i) {
+ lcd.write(temp[i]);
+ }
+#endif
+#endif // HAS_LCD
+}
+
+
+void LCD_main_menu() {
+#ifdef HAS_LCD
+ lcd_dirty=1;
+
+ MENU_START
+
+ MENU_SUBMENU("Back", LCD_status_menu);
+#ifdef HAS_SD
+ if (!sd_printing_now) {
+#endif
+#if MACHINE_HARDWARE_VERSION == 5
+ MENU_ACTION("Find home", LCD_find_home);
+#else
+ MENU_ACTION("This is home", LCD_this_is_home);
+ MENU_ACTION("Go home", LCD_go_home);
+#endif
+#ifdef HAS_SD
+ if (sd_inserted) {
+ MENU_SUBMENU("Print from SD card", LCD_start_menu);
+ } else {
+ MENU_LABEL("No SD card");
+ }
+#endif
+#if NUM_AXIES == 3
+ MENU_SUBMENU("Draw border", LCD_draw_border);
+#endif
+ MENU_SUBMENU("Drive", LCD_drive_menu);
+#ifdef HAS_SD
+ } else {
+ if (sd_printing_paused) {
+ MENU_ACTION("Unpause", LCD_pause);
+ } else {
+ MENU_ACTION("Pause", LCD_pause);
+ }
+ MENU_ACTION("Stop", LCD_stop);
+ }
+#endif
+ MENU_END
+#endif // HAS_LCD
+}
+
+
+// display the current machine position and feed rate on the LCD.
+void LCD_status_menu() {
+#ifdef HAS_LCD
+ MENU_START
+
+ // on click go to the main menu
+ if (lcd_click_now) MENU_GOTO(LCD_main_menu);
+
+ if (lcd_turn) {
+ speed_adjust += lcd_turn;
+ }
+ LCD_setCursor( 0, 0);
+
+ // update the current status
+ float offset[NUM_AXIES];
+ get_end_plus_offset(offset);
+
+ LCD_setCursor(0, 0); LCD_print('X'); LCD_print_float(offset[0]);
+ LCD_setCursor(9, 0); LCD_print('Z'); LCD_print_float(offset[2]);
+#if MACHINE_STYLE == POLARGRAPH && defined(USE_LIMIT_SWITCH)
+ LCD_setCursor(8, 0); LCD_print(( digitalRead(LIMIT_SWITCH_PIN_LEFT) == LOW ) ? '*' : ' ');
+#endif
+
+ LCD_setCursor(0, 1); LCD_print('Y'); LCD_print_float(offset[1]);
+ LCD_setCursor(9, 1); LCD_print('F'); LCD_print_long(speed_adjust); LCD_print('%');
+#if MACHINE_STYLE == POLARGRAPH && defined(USE_LIMIT_SWITCH)
+ LCD_setCursor(8, 1); LCD_print(( digitalRead(LIMIT_SWITCH_PIN_RIGHT) == LOW ) ? '*' : ' ');
+#endif
+
+ //LCD_setCursor( 1, 15);
+ //if (sd_printing_now == true && sd_printing_paused==false) {
+ //if (sd_printing_now == true) {
+ //LCD_print_float(sd_percent_complete);
+ //LCD_print('%');
+ //} else {
+ //LCD_print(" ");
+ //}
+ MENU_END
+#endif // HAS_LCD
+}
+
+
+// initialize the Smart controller LCD panel
+void LCD_setup() {
+#ifdef HAS_LCD
+
+#ifdef LCD_IS_SMART
+ lcd.begin(LCD_WIDTH, LCD_HEIGHT);
+#endif
+#ifdef LCD_IS_128X64
+ u8g.begin();
+ u8g.disableCursor();
+ u8g.setFont(u8g_font_6x9);
+ // u8g.setFont(u8g_font_helvR08);
+#endif
+
+ pinMode(BEEPER, OUTPUT);
+ digitalWrite(BEEPER, LOW);
+
+ pinMode(BTN_EN1, INPUT);
+ pinMode(BTN_EN2, INPUT);
+ pinMode(BTN_ENC, INPUT);
+ digitalWrite(BTN_EN1, HIGH);
+ digitalWrite(BTN_EN2, HIGH);
+ digitalWrite(BTN_ENC, HIGH);
+ current_menu = LCD_status_menu;
+ menu_position_sum = 1; /* 20160313-NM-Added so the clicking without any movement will display a menu */
+
+ LCD_drawSplash();
+
+ LCD_read();
+ lcd_turn=0;
+ LCD_clear();
+#endif // HAS_LCD
+}
+
+
+#ifdef HAS_LCD
+void LCD_drawSplash() {
+ // splash screen
+ char message[LCD_WIDTH];
+ char mhv[12];
+ itoa(MACHINE_HARDWARE_VERSION, mhv, 10);
+ char *ptr = message;
+ strcpy(ptr, MACHINE_STYLE_NAME ); ptr += strlen(MACHINE_STYLE_NAME);
+ strcpy(ptr, " v" ); ptr += strlen(" v");
+ strcpy(ptr, mhv ); ptr += strlen(mhv);
+
+ int x = (LCD_WIDTH - strlen(message)) / 2;
+ int y = LCD_HEIGHT - 2;
+ int x2 = (LCD_WIDTH - strlen("marginallyclever.com")) / 2;
+ int y2 = y + 1;
+
+#ifdef LCD_IS_128X64
+ u8g.firstPage();
+ do {
+#endif
+ LCD_clear();
+#ifdef LCD_IS_128X64
+ u8g.drawBitmapP((LCD_PIXEL_WIDTH - logoImageWidth) / 2, 0, logoImageWidth / 8, logoImageHeight, logoImage);
+#endif
+ LCD_setCursor(x, y);
+ LCD_print(message);
+ LCD_setCursor(x2, y2);
+ LCD_print("marginallyclever.com");
+#ifdef LCD_IS_128X64
+ } while (u8g.nextPage());
+#endif
+ LCD_refresh_display();
+ delay(2500);
+}
+#endif // HAS_LCD
diff --git a/lcd.h b/lcd.h
index 818facd..4e4f038 100644
--- a/lcd.h
+++ b/lcd.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@@ -12,10 +11,7 @@
//------------------------------------------------------------------------------
#ifdef HAS_LCD
-// only uncomment one of these options
-#define LCD_IS_128X64 // reprapdiscount Full Graphic Smart LCD Controller
-//#define LCD_IS_SMART // reprapdiscount Smart LCD Controller (including XXL model)
-
+#include
//----------------------------------------------------
@@ -29,8 +25,8 @@
#define FONT_WIDTH 6
// # of characters
-#define LCD_HEIGHT (LCD_PIXEL_HEIGHT/FONT_HEIGHT)
-#define LCD_WIDTH (LCD_PIXEL_WIDTH/FONT_WIDTH)
+#define LCD_HEIGHT (LCD_PIXEL_HEIGHT/FONT_HEIGHT) // 64/9=7
+#define LCD_WIDTH (LCD_PIXEL_WIDTH/FONT_WIDTH) // 128/6=21
#include "dogm_font_data_6x9.h"
@@ -68,12 +64,16 @@
#define ENCROT2 3
#define ENCROT3 1
-#define LCD_MESSAGE_LENGTH (LCD_HEIGHT * (LCD_WIDTH + 1)) // we have two lines of 20 characters avialable in 7.16
+#define LCD_MESSAGE_LENGTH (LCD_HEIGHT * LCD_WIDTH + 1) // we have two lines of 20 characters avialable in 7.16
#define LCD_DRAW_DELAY (100)
#define LCD_TURN_PER_MENU (5)
extern char lcd_message[LCD_MESSAGE_LENGTH+1];
+extern uint8_t speed_adjust;
#endif // HAS_LCD
+extern void LCD_update();
+extern void LCD_setup();
+
#endif // LCD_H
diff --git a/lcd.ino b/lcd.ino
deleted file mode 100644
index 407ed42..0000000
--- a/lcd.ino
+++ /dev/null
@@ -1,688 +0,0 @@
-//------------------------------------------------------------------------------
-// Makelangelo - firmware for various robot kinematic models
-// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
-//------------------------------------------------------------------------------
-
-//------------------------------------------------------------------------------
-// INCLUDES
-//------------------------------------------------------------------------------
-#ifdef HAS_LCD
-#include "lcd.h"
-
-#include "sdcard.h"
-
-#ifdef LCD_IS_SMART
-#include
-#endif
-#ifdef LCD_IS_128X64
-#include
-#include
-#include
-#include
-#include "dogm_font_data_6x9.h"
-#endif
-
-//------------------------------------------------------------------------------
-// GLOBALS
-//------------------------------------------------------------------------------
-#ifdef LCD_IS_SMART
-LiquidCrystal lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7);
-#endif
-#ifdef LCD_IS_128X64
-// This is not ideal - will not work when board models change.
-U8GLIB_ST7920_128X64_1X u8g(LCD_PINS_D4,LCD_PINS_ENABLE,LCD_PINS_RS);
-
-
-/**
- * Made with Marlin Bitmap Converter
- * http://marlinfw.org/tools/u8glib/converter.html
- *
- * This bitmap from the file 'icon_mono.png'
- * Filesize: 906 Bytes
- * Size bitmap: 108 bytes
- */
-#define logoImageWidth 32
-#define logoImageHeight 32
-
-const unsigned char logoImage [] PROGMEM= {
- 0x00,0x60,0x00,0x00, // .........##.....................
- 0x00,0xF0,0x00,0x00, // ........####....................
- 0x03,0x10,0x00,0x00, // ......##...#....................
- 0x01,0x60,0x00,0x00, // .......#.##.....................
- 0x01,0xC0,0x00,0x00, // .......###......................
- 0x00,0x9F,0xF0,0x00, // ........#..#########............
- 0x00,0xF0,0x3C,0x00, // ........####......####..........
- 0x01,0xC0,0x3F,0x00, // .......###........######........
- 0x03,0x00,0x1F,0x80, // ......##...........######.......
- 0x06,0x00,0x1F,0xC0, // .....##............#######......
- 0x0C,0x02,0x0F,0xE0, // ....##........#.....#######.....
- 0x08,0x06,0x0F,0xE0, // ....#........##.....#######.....
- 0x18,0x02,0x0F,0xF0, // ...##.........#.....########....
- 0x10,0x02,0x0F,0xF0, // ...#..........#.....########....
- 0x31,0x80,0x07,0xF0, // ..##...##............#######....
- 0x23,0x80,0x07,0xF8, // ..#...###............########...
- 0x23,0x00,0x07,0xF8, // ..#...##.............########...
- 0x23,0x00,0x07,0xF8, // ..#...##.............########...
- 0x23,0x00,0x07,0xF8, // ..#...##.............########...
- 0x21,0x80,0x07,0xF8, // ..#....##............########...
- 0x20,0x00,0x07,0xF8, // ..#..................########...
- 0x30,0x00,0x37,0xF8, // ..##..............##.########...
- 0x30,0x00,0x63,0xF0, // ..##.............##...######....
- 0x10,0x00,0x63,0xF0, // ...#.............##...######....
- 0x18,0x00,0x63,0xF0, // ...##............##...######....
- 0x08,0x60,0x37,0xE0, // ....#....##.......##.######.....
- 0x04,0x20,0x0F,0xC0, // .....#....#.........######......
- 0x06,0x00,0x1F,0xC0, // .....##............#######......
- 0x03,0x00,0x1F,0x80, // ......##...........######.......
- 0x00,0xC0,0x3E,0x00, // ........##........#####.........
- 0x00,0x70,0x3C,0x00, // .........###......####..........
- 0x00,0x1F,0xE0,0x00 // ...........########.............
-};
-#endif
-
-//------------------------------------------------------------------------------
-// MACROS
-//------------------------------------------------------------------------------
-
-/**
- * Clear the screen
- */
-#ifdef LCD_IS_SMART
-#define LCD_clear() lcd.clear()
-#endif
-#ifdef LCD_IS_128X64
-void LCD_clear() {
- //u8g.firstPage();
- //while( u8g.nextPage() );
- u8g.setColorIndex(0);
- u8g.drawBox(0,0,LCD_PIXEL_WIDTH,LCD_PIXEL_HEIGHT);
- u8g.setColorIndex(1);
-}
-#endif
-
-/**
- * print text to the LCD
- */
-#ifdef LCD_IS_SMART
-#define LCD_print lcd.print
-#endif
-#ifdef LCD_IS_128X64
-#define LCD_print u8g.print
-#endif
-
-
-/**
- * Set the row/column of text at which to begin printing
- */
-#ifdef LCD_IS_SMART
-#define LCD_setCursor(x,y) lcd.setCursor(x,y)
-#endif
-#ifdef LCD_IS_128X64
-#define LCD_setCursor(x,y) u8g.setPrintPos(((x)+1)*FONT_WIDTH,((y)+1)*FONT_HEIGHT)
-#endif
-
-
-
-// Convenience macros that make it easier to generate menus
-
-#define MENU_START \
- ty=0;
-
-#define MENU_END \
- num_menu_items=ty; \
-
-#define MENU_ITEM_START(key) \
- if(ty>=screen_position && ty':' '); \
- LCD_print(key); \
-
-#define MENU_ITEM_END() \
- } \
- ++ty;
-
-#define MENU_GOTO(new_menu) { \
- lcd_click_now=false; \
- LCD_clear(); \
- num_menu_items=screen_position=menu_position=menu_position_sum=0; \
- screen_end = screen_position + LCD_HEIGHT; \
- current_menu=new_menu; \
- return; \
- }
-
-#define MENU_SUBMENU(menu_label,menu_method) \
- MENU_ITEM_START(menu_label) \
- if(menu_position==ty && lcd_click_now) MENU_GOTO(menu_method); \
- MENU_ITEM_END()
-
-#define MENU_ACTION(menu_label,menu_method) MENU_SUBMENU(menu_label,menu_method)
-
-#define MENU_LONG(key,value) \
- MENU_ITEM_START(key) \
- LCD_print_long(value); \
- if(menu_position==ty && lcd_click_now) LCD_update_long(key,value); \
- MENU_ITEM_END()
-
-#define MENU_FLOAT(key,value) \
- MENU_ITEM_START(key) \
- LCD_print_float(value); \
- if(menu_position==ty && lcd_click_now) LCD_update_float(key,value); \
- MENU_ITEM_END()
-
-
-//------------------------------------------------------------------------------
-// GLOBALS
-//------------------------------------------------------------------------------
-
-long lcd_draw_delay = 0;
-
-int lcd_rot_old = 0;
-int lcd_turn = 0;
-char lcd_click_old = HIGH;
-char lcd_click_now = false;
-uint8_t speed_adjust = 100;
-char lcd_message[LCD_MESSAGE_LENGTH+1];
-
-int menu_position_sum = 0, menu_position = 0, screen_position = 0, num_menu_items = 0, ty, screen_end;
-
-
-void (*current_menu)();
-
-
-//------------------------------------------------------------------------------
-// METHODS
-//------------------------------------------------------------------------------
-
-
-void LCD_read() {
- // detect potentiometer changes
- int rot = ((digitalRead(BTN_EN1) == LOW) << BLEN_A)
- | ((digitalRead(BTN_EN2) == LOW) << BLEN_B);
- // potentiometer uses grey code. Pattern is 0 3
- switch (rot) {
- case ENCROT0:
- if ( lcd_rot_old == ENCROT3 ) lcd_turn++;
- if ( lcd_rot_old == ENCROT1 ) lcd_turn--;
- break;
- case ENCROT1:
- if ( lcd_rot_old == ENCROT0 ) lcd_turn++;
- if ( lcd_rot_old == ENCROT2 ) lcd_turn--;
- break;
- case ENCROT2:
- if ( lcd_rot_old == ENCROT1 ) lcd_turn++;
- if ( lcd_rot_old == ENCROT3 ) lcd_turn--;
- break;
- case ENCROT3:
- if ( lcd_rot_old == ENCROT2 ) lcd_turn++;
- if ( lcd_rot_old == ENCROT0 ) lcd_turn--;
- break;
- }
- if(lcd_rot_old != rot) {
- //if(lcd_turn !=0) Serial.print(lcd_turn>0?'+':'-'); // for debugging potentiometer
- //Serial.println(rot); // for debugging potentiometer
- }
-
- lcd_rot_old = rot;
-
-
- // find click state
- int btn = digitalRead(BTN_ENC);
- if ( btn != lcd_click_old && btn == HIGH ) {
- lcd_click_now = true;
- }
- lcd_click_old = btn;
-}
-
-
-// display the current machine position and feed rate on the LCD.
-void LCD_status_menu() {
- MENU_START
-
- // on click go to the main menu
- if (lcd_click_now) MENU_GOTO(LCD_main_menu);
-
- if (lcd_turn) {
- speed_adjust += lcd_turn;
- }
-
- // update the current status
- float offset[NUM_AXIES];
- get_end_plus_offset(offset);
- LCD_setCursor( 0, 0); LCD_print('X'); LCD_print_float(offset[0]);
- LCD_setCursor(10, 0); LCD_print('Z'); LCD_print_float(offset[2]);
-#if MACHINE_STYLE == POLARGRAPH && defined(USE_LIMIT_SWITCH)
- LCD_setCursor(19, 0); LCD_print(( digitalRead(LIMIT_SWITCH_PIN_LEFT) == LOW ) ? '*':' ');
-#endif
-
- LCD_setCursor( 0, 1); LCD_print('Y'); LCD_print_float(offset[1]);
- LCD_setCursor(10, 1); LCD_print('F'); LCD_print_long(speed_adjust); LCD_print(F("% "));
-#if MACHINE_STYLE == POLARGRAPH && defined(USE_LIMIT_SWITCH)
- LCD_setCursor(19, 1); LCD_print(( digitalRead(LIMIT_SWITCH_PIN_RIGHT) == LOW ) ? '*':' ');
-#endif
-
-
- //LCD_setCursor(10, 1); LCD_print('F'); LCD_print_float(feed_rate);
- //LCD_setCursor( 0, 1); LCD_print(F("Makelangelo #")); LCD_print(robot_uid);
- LCD_setCursor( 0, 2);
- if (sd_printing_now == true/* && sd_printing_paused==false*/) {
- LCD_print_float(sd_percent_complete);
- LCD_print('%');
- } else {
- LCD_print(F(" "));
- }
- LCD_print_message();
- MENU_END
-}
-
-
-void LCD_main_menu() {
- MENU_START
-
- MENU_SUBMENU("Back", LCD_status_menu);
- if (!sd_printing_now) {
- MENU_ACTION("Disable motors", LCD_disable_motors);
- MENU_ACTION("Enable motors", LCD_enable_motors);
-#if MACHINE_HARDWARE_VERSION == 5
- MENU_ACTION("Find home", LCD_find_home);
-#else
- MENU_ACTION("This is home", LCD_this_is_home);
- MENU_ACTION("Go home", LCD_go_home);
-#endif
- if (sd_inserted) {
- MENU_SUBMENU("Draw *.NGC file...", LCD_start_menu);
- }
- MENU_SUBMENU("Drive", LCD_drive_menu);
- } else {
- if (sd_printing_paused) {
- MENU_ACTION("Unpause", LCD_pause);
- } else {
- MENU_ACTION("Pause", LCD_pause);
- }
- MENU_ACTION("Stop", LCD_stop);
- }
- MENU_END
-}
-
-
-void LCD_print_message() {
- lcd_message[LCD_MESSAGE_LENGTH - 1] = 0;
- LCD_setCursor( 0, 2); LCD_print(lcd_message);
- LCD_setCursor( 0, 3); LCD_print(lcd_message + LCD_WIDTH + 1);
-}
-
-
-void LCD_pause() {
- sd_printing_paused = (sd_printing_paused == true ? false : true);
- MENU_GOTO(LCD_main_menu);
-}
-
-
-void LCD_stop() {
- sd_printing_now = false;
- MENU_GOTO(LCD_main_menu);
-}
-
-void LCD_disable_motors() {
- motor_disengage();
- MENU_GOTO(LCD_main_menu);
-}
-
-void LCD_enable_motors() {
- motor_engage();
- MENU_GOTO(LCD_main_menu);
-}
-
-
-void LCD_find_home() {
- robot_findHome();
- MENU_GOTO(LCD_main_menu);
-}
-
-
-void LCD_this_is_home() {
- float offset[NUM_AXIES];
- for (int i = 0; i < NUM_AXIES; ++i) offset[i] = axies[i].homePos;
- teleport(offset);
- MENU_GOTO(LCD_main_menu);
-}
-
-
-void LCD_go_home() {
- float homes[NUM_AXIES];
- for (int i = 0; i < NUM_AXIES; ++i) homes[i] = axies[i].homePos;
- lineSafe( homes, DEFAULT_FEEDRATE );
- MENU_GOTO(LCD_main_menu);
-}
-
-
-void LCD_drive_menu() {
- MENU_START
- MENU_SUBMENU("Back", LCD_main_menu);
- MENU_SUBMENU("X", LCD_driveX);
- MENU_SUBMENU("Y", LCD_driveY);
- MENU_SUBMENU("Z", LCD_driveZ);
- MENU_SUBMENU("Feedrate", LCD_driveF);
- MENU_END
-}
-
-
-void LCD_driveX() {
- if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
-
- float offset[NUM_AXIES];
- get_end_plus_offset(offset);
-
- if (lcd_turn) {
- offset[0] += lcd_turn > 0 ? 1 : -1;
- lineSafe(offset, feed_rate);
- }
-
- LCD_setCursor( 0, 0);
- LCD_print('X');
- LCD_print_float(offset[0]);
-}
-
-
-void LCD_driveY() {
- if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
-
- float offset[NUM_AXIES];
- get_end_plus_offset(offset);
-
- if (lcd_turn) {
- offset[1] += lcd_turn > 0 ? 1 : -1;
- lineSafe(offset, feed_rate);
- }
-
- LCD_setCursor( 0, 0);
- LCD_print('Y');
- LCD_print_float(offset[1]);
-}
-
-
-void LCD_driveZ() {
- if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
-
- float offset[NUM_AXIES];
- get_end_plus_offset(offset);
-
- if (lcd_turn) {
- // protect servo, don't drive beyond physical limits
- offset[2] += lcd_turn > 0 ? 1 : -1;
- lineSafe(offset, feed_rate);
- }
-
- LCD_setCursor( 0, 0);
- LCD_print('Z');
- LCD_print_float(offset[2]);
-}
-
-
-void LCD_driveF() {
- if (lcd_click_now) MENU_GOTO(LCD_drive_menu);
-
- if (lcd_turn) {
- // protect servo, don't drive beyond physical limits
- float newF = feed_rate + (lcd_turn > 0 ? 1 : -1);
- if (newF < MIN_FEEDRATE) newF = MIN_FEEDRATE;
- if (newF > MAX_FEEDRATE) newF = MAX_FEEDRATE;
- // move
- feed_rate = newF;
- }
-
- LCD_setCursor( 0, 0);
- LCD_print('F');
- LCD_print_float(feed_rate);
-}
-
-
-void LCD_start_menu() {
- if (!sd_inserted) MENU_GOTO(LCD_main_menu);
-
- MENU_START
- MENU_SUBMENU("Back", LCD_main_menu);
- /*
- Serial.print(menu_position ); Serial.print("\t"); // 0
- Serial.print(menu_position_sum); Serial.print("\t"); // 1
- Serial.print(screen_position ); Serial.print("\t"); // 0
- Serial.print(num_menu_items ); Serial.print("\n"); // 8
- */
-
- root.rewindDirectory();
- while ( true ) {
- //long tStart = millis();
- File entry = root.openNextFile();
- //long tEnd = millis();
- //Serial.print(tEnd-tStart);
- //Serial.print('\t');
- if (!entry) {
- // no more files, return to the first file in the directory
- break;
- }
- char *filename = entry.name();
- //Serial.print( entry.isDirectory()?">":" " );
- //Serial.println(filename);/*
- if (!entry.isDirectory() && filename[0] != '_') {
- MENU_ITEM_START(filename)
- if (menu_position == ty && lcd_click_now) {
- lcd_click_now = false;
- SD_StartPrintingFile(filename);
- MENU_GOTO(LCD_status_menu);
- }
- MENU_ITEM_END()
- }
- entry.close();
- }
-
- //Serial.println();
-
-
- MENU_END
-}
-
-void LCD_update_long(char *label, long &value) {
- LCD_clear();
- do {
- LCD_read();
- if ( lcd_turn ) {
- value += lcd_turn > 0 ? 1 : -1;
- lcd_turn = 0;
- }
- LCD_setCursor(0, 0);
- LCD_print(label);
- LCD_setCursor(0, 1);
- LCD_print_long(value);
- } while ( !lcd_click_now );
-}
-
-
-void LCD_update_float(char *label, float &value,float stepSize=0.01) {
- LCD_clear();
- do {
- LCD_read();
- if ( lcd_turn ) {
- value += lcd_turn > 0 ? stepSize : -stepSize;
- lcd_turn = 0;
- }
- LCD_setCursor(0, 0);
- LCD_print(label);
- LCD_setCursor(0, 1);
- LCD_print_float(value);
- } while ( !lcd_click_now );
-}
-
-
-void LCD_print_long(long v) {
- long av = abs(v);
- int x = 1000;
- while (x > av && x > 1) {
- LCD_print(' ');
- x /= 10;
- };
- if (v > 0) LCD_print(' ');
- LCD_print(v);
-}
-
-
-
-void LCD_print_float(float v) {
- int left = abs(v);
- int right = abs((int)(v * 100) % 100);
-
- if (left < 1000) LCD_print(' ');
- if (left < 100) LCD_print(' ');
- if (left < 10) LCD_print(' ');
- if (v < 0) LCD_print('-');
- else LCD_print(' ');
- LCD_print(left);
- LCD_print('.');
- if (right < 10) LCD_print('0');
- LCD_print(right);
-}
-#endif // HAS_LCD
-
-
-
-
-void LCD_update() {
-#ifdef HAS_LCD
- LCD_read();
-
- if (millis() >= lcd_draw_delay ) {
- lcd_draw_delay = millis() + LCD_DRAW_DELAY;
-
- //Serial.print(lcd_turn,DEC);
- //Serial.print('\t'); Serial.print(menu_position,DEC);
- //Serial.print('\t'); Serial.print(menu_position_sum,DEC);
- //Serial.print('\t'); Serial.print(screen_position,DEC);
- //Serial.print('\t'); Serial.print(screen_end,DEC);
- //Serial.print('\t'); Serial.print(num_menu_items,DEC);
- //Serial.print('\n');
-
- // update the menu position
- if ( lcd_turn && num_menu_items>1 ) {
- int originalPosition = menu_position_sum / LCD_TURN_PER_MENU;
- menu_position_sum += lcd_turn;
-
- menu_position = menu_position_sum / LCD_TURN_PER_MENU;
- if (menu_position > num_menu_items - 1) menu_position = num_menu_items - 1;
- if (menu_position < 0) menu_position = 0;
-
- if (originalPosition != menu_position) {
- LCD_clear();
- }
-
- Serial.println(menu_position);
-
- if (screen_position > menu_position) screen_position = menu_position;
- if (screen_position < menu_position - (LCD_HEIGHT - 1)) screen_position = menu_position - (LCD_HEIGHT - 1);
- screen_end = screen_position + LCD_HEIGHT;
- }
-
- // draw the new screen contents
-#ifdef LCD_IS_128X64
- u8g.firstPage();
- do {
-#endif
- (*current_menu)();
-#ifdef LCD_IS_128X64
- } while(u8g.nextPage());
-#endif
-
- lcd_turn = 0; // reset. must come after (*current_menu)() because it might be used there. (damn globals...)
- }
-#endif // HAS_LCD
-}
-
-// initialize the Smart controller LCD panel
-void LCD_init() {
-#ifdef HAS_LCD
-
-#ifdef LCD_IS_SMART
- lcd.begin(LCD_WIDTH, LCD_HEIGHT);
-#endif
-#ifdef LCD_IS_128X64
- u8g.begin();
- u8g.disableCursor();
- u8g.setFont(u8g_font_6x9);
-// u8g.setFont(u8g_font_helvR08);
-#endif
-
- pinMode(BEEPER,OUTPUT);
- digitalWrite(BEEPER,LOW);
-
- pinMode(BTN_EN1, INPUT);
- pinMode(BTN_EN2, INPUT);
- pinMode(BTN_ENC, INPUT);
- digitalWrite(BTN_EN1, HIGH);
- digitalWrite(BTN_EN2, HIGH);
- digitalWrite(BTN_ENC, HIGH);
- current_menu = LCD_status_menu;
- menu_position_sum = 1; /* 20160313-NM-Added so the clicking without any movement will display a menu */
-
- lcd_message[0]=0;
-
- LCD_drawSplash();
- //LCD_drawSplash();
-
-#endif // HAS_LCD
-}
-
-
-#ifdef HAS_LCD
-void LCD_drawSplash() {
- // splash screen
- char message[LCD_WIDTH];
- char mhv[10];
- itoa(MACHINE_HARDWARE_VERSION,mhv,10);
- char *ptr = message;
- strcpy(ptr, MACHINE_STYLE_NAME ); ptr += strlen(MACHINE_STYLE_NAME);
- strcpy(ptr, " v" ); ptr += strlen(" v");
- strcpy(ptr, mhv ); ptr += strlen(mhv);
-
- int x = (LCD_WIDTH - strlen(message)) / 2;
- int y = LCD_HEIGHT-2;
- int x2 = (LCD_WIDTH - strlen("marginallyclever.com")) / 2;
- int y2 = y+1;
-
-#ifdef LCD_IS_128X64
- u8g.firstPage();
- do {
-#endif
- LCD_clear();
-#ifdef LCD_IS_128X64
- u8g.drawBitmapP((LCD_PIXEL_WIDTH-logoImageWidth)/2,0,logoImageWidth/8,logoImageHeight,logoImage);
-#endif
- LCD_setCursor(x,y);
- LCD_print(message);
- LCD_setCursor(x2,y2);
- LCD_print("marginallyclever.com");
-#ifdef LCD_IS_128X64
- } while(u8g.nextPage());
-#endif
-
- delay(2500);
- LCD_clear();
-}
-#endif
-
-
-/**
- This file is part of makelangelo-firmware.
-
- makelangelo-firmware is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- makelangelo-firmware is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with makelangelo-firmware. If not, see .
-*/
-
diff --git a/motor.cpp b/motor.cpp
new file mode 100644
index 0000000..6fa507d
--- /dev/null
+++ b/motor.cpp
@@ -0,0 +1,1200 @@
+//------------------------------------------------------------------------------
+// Makelangelo - firmware for various robot kinematic models
+// dan@marginallycelver.com 2013-12-26
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// INCLUDES
+//------------------------------------------------------------------------------
+#include "configure.h"
+#include "motor.h"
+#include "MServo.h"
+#include "LCD.h"
+
+//------------------------------------------------------------------------------
+// MACROS
+//------------------------------------------------------------------------------
+
+#ifdef ESP8266
+#define CLOCK_ADJUST(x) { timer0_write(ESP.getCycleCount() + (long) (80000L*(x)) ); } // microseconds
+#else
+#define CLOCK_ADJUST(x) { OCR1A = (x); } // microseconds
+#endif
+
+//------------------------------------------------------------------------------
+// DEFINES
+//------------------------------------------------------------------------------
+
+#define BLOCK_DELAY_FOR_1ST_MOVE 100
+#define MIN_STEP_RATE 120
+
+//------------------------------------------------------------------------------
+// GLOBALS
+//------------------------------------------------------------------------------
+
+Motor motors[NUM_MOTORS + NUM_SERVOS];
+#ifndef ESP8266
+Servo servos[NUM_SERVOS];
+#endif
+
+Segment line_segments[MAX_SEGMENTS];
+Segment *working_seg = NULL;
+volatile int current_segment = 0;
+volatile int last_segment = 0;
+int first_segment_delay;
+
+// used by timer1 to optimize interrupt inner loop
+int steps_total;
+int steps_taken;
+int accel_until, decel_after;
+uint32_t current_feed_rate;
+uint32_t current_acceleration;
+uint32_t start_feed_rate, end_feed_rate, isr_nominal_rate;
+uint32_t time_accelerating, time_decelerating;
+float max_xy_jerk = MAX_JERK;
+float max_feedrate_mm_s[NUM_MOTORS + NUM_SERVOS];
+uint8_t isr_step_multiplier = 1;
+
+int delta0;
+int over0;
+long global_steps_0;
+int global_step_dir_0;
+#if NUM_MOTORS>1
+int delta1;
+int over1;
+long global_steps_1;
+int global_step_dir_1;
+#endif
+#if NUM_MOTORS>2
+int delta2;
+int over2;
+long global_steps_2;
+int global_step_dir_2;
+#endif
+#if NUM_MOTORS>3
+int delta3;
+int over3;
+long global_steps_3;
+int global_step_dir_3;
+#endif
+#if NUM_MOTORS>4
+int delta4;
+int over4;
+long global_steps_4;
+int global_step_dir_4;
+#endif
+#if NUM_MOTORS>5
+int delta5;
+int over5;
+long global_steps_5;
+int global_step_dir_5;
+#endif
+
+float previous_nominal_speed = 0;
+float previous_safe_speed = 0;
+float previous_speed[NUM_MOTORS + NUM_SERVOS];
+
+const char *MotorNames = "LRUVWT";
+const char *AxisNames = "XYZUVWT";
+float maxFeedRate[NUM_MOTORS];
+
+
+//------------------------------------------------------------------------------
+// METHODS
+//------------------------------------------------------------------------------
+#ifdef ESP8266
+void itr();
+#endif
+
+
+const int movesPlanned() {
+ return SEGMOD( last_segment - current_segment );
+}
+
+// for reasons I don't understand... if i put this method in the .h file i get compile errors.
+// so I put it here, which forces the externs.
+FORCE_INLINE Segment *get_current_segment() {
+ if (current_segment == last_segment ) return NULL;
+ if (first_segment_delay > 0) {
+ --first_segment_delay;
+ if (movesPlanned() > 3) first_segment_delay = 0;
+ return NULL;
+ }
+ return &line_segments[current_segment];
+}
+
+
+FORCE_INLINE int get_next_segment(int i) {
+ return SEGMOD( i + 1 );
+}
+
+
+FORCE_INLINE int get_prev_segment(int i) {
+ return SEGMOD( i - 1 );
+}
+
+/**
+ Calculate the maximum allowable speed at this point, in order
+ to reach 'target_velocity' using 'acceleration' within a given
+ 'distance'.
+ @param acc acceleration
+ @param target_velocity
+ @param distance
+*/
+float max_speed_allowed(const float &acc, const float &target_velocity, const float &distance) {
+ return sqrt( sq(target_velocity) - 2 * acc * distance );
+}
+
+
+/**
+ set up the pins for each motor
+*/
+void motor_setup() {
+ motors[0].step_pin = MOTOR_0_STEP_PIN;
+ motors[0].dir_pin = MOTOR_0_DIR_PIN;
+ motors[0].enable_pin = MOTOR_0_ENABLE_PIN;
+ motors[0].limit_switch_pin = MOTOR_0_LIMIT_SWITCH_PIN;
+#if NUM_MOTORS>1
+ motors[1].step_pin = MOTOR_1_STEP_PIN;
+ motors[1].dir_pin = MOTOR_1_DIR_PIN;
+ motors[1].enable_pin = MOTOR_1_ENABLE_PIN;
+ motors[1].limit_switch_pin = MOTOR_1_LIMIT_SWITCH_PIN;
+#endif
+#if NUM_MOTORS>2
+ motors[2].step_pin = MOTOR_2_STEP_PIN;
+ motors[2].dir_pin = MOTOR_2_DIR_PIN;
+ motors[2].enable_pin = MOTOR_2_ENABLE_PIN;
+ motors[2].limit_switch_pin = MOTOR_2_LIMIT_SWITCH_PIN;
+#endif
+#if NUM_MOTORS>3
+ motors[3].step_pin = MOTOR_3_STEP_PIN;
+ motors[3].dir_pin = MOTOR_3_DIR_PIN;
+ motors[3].enable_pin = MOTOR_3_ENABLE_PIN;
+ motors[3].limit_switch_pin = MOTOR_3_LIMIT_SWITCH_PIN;
+#endif
+#if NUM_MOTORS>4
+ motors[4].step_pin = MOTOR_4_STEP_PIN;
+ motors[4].dir_pin = MOTOR_4_DIR_PIN;
+ motors[4].enable_pin = MOTOR_4_ENABLE_PIN;
+ motors[4].limit_switch_pin = MOTOR_4_LIMIT_SWITCH_PIN;
+#endif
+#if NUM_MOTORS>5
+ motors[5].step_pin = MOTOR_5_STEP_PIN;
+ motors[5].dir_pin = MOTOR_5_DIR_PIN;
+ motors[5].enable_pin = MOTOR_5_ENABLE_PIN;
+ motors[5].limit_switch_pin = MOTOR_5_LIMIT_SWITCH_PIN;
+#endif
+
+ Serial.println(" set pins");
+
+ int i;
+ for (i = 0; i < NUM_MOTORS; ++i) {
+ // set the motor pin & scale
+ //pinMode(motors[i].step_pin, OUTPUT);
+ //pinMode(motors[i].dir_pin, OUTPUT);
+ //pinMode(motors[i].enable_pin, OUTPUT);
+ delay(100);
+
+ // set the switch pin
+ //pinMode(motors[i].limit_switch_pin, INPUT);
+ //digitalWrite(motors[i].limit_switch_pin, HIGH);
+ }
+
+ long steps[NUM_MOTORS + NUM_SERVOS];
+ memset(steps, 0, (NUM_MOTORS + NUM_SERVOS)*sizeof(long));
+
+ for (i = 0; i < NUM_MOTORS; ++i) {
+ max_feedrate_mm_s[i] = MAX_FEEDRATE;
+ }
+ for (i = NUM_MOTORS; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ max_feedrate_mm_s[i] = MAX_FEEDRATE;
+ }
+
+ Serial.println(" motor_set_step_count()");
+ motor_set_step_count(steps);
+
+ // setup servos
+#if NUM_SERVOS>0
+#ifdef ESP8266
+ pinMode(SERVO0_PIN, OUTPUT);
+#else
+ servos[0].attach(SERVO0_PIN);
+#endif // ESP8266
+#endif
+
+#if NUM_SERVOS>1
+ servos[1].attach(SERVO1_PIN);
+#endif
+#if NUM_SERVOS>2
+ servos[2].attach(SERVO2_PIN);
+#endif
+#if NUM_SERVOS>3
+ servos[3].attach(SERVO3_PIN);
+#endif
+#if NUM_SERVOS>4
+ servos[4].attach(SERVO4_PIN);
+#endif
+
+ current_segment = 0;
+ last_segment = 0;
+ Segment &old_seg = line_segments[get_prev_segment(last_segment)];
+ old_seg.a[0].step_count = 0;
+#if NUM_MOTORS>1
+ old_seg.a[1].step_count = 0;
+#endif
+#if NUM_MOTORS>2
+ old_seg.a[2].step_count = 0;
+#endif
+#if NUM_MOTORS>3
+ old_seg.a[3].step_count = 0;
+#endif
+#if NUM_MOTORS>4
+ old_seg.a[4].step_count = 0;
+#endif
+#if NUM_MOTORS>5
+ old_seg.a[5].step_count = 0;
+#endif
+
+#if NUM_SERVOS>0
+ old_seg.a[NUM_MOTORS].step_count = 0;
+#endif
+
+ working_seg = NULL;
+ first_segment_delay = 0;
+
+ Serial.println(" interrupt setup");
+
+ // disable global interrupts
+ noInterrupts();
+#ifdef ESP8266
+ timer0_isr_init();
+ timer0_attachInterrupt(itr);
+ CLOCK_ADJUST(2000);
+#else
+ // set entire TCCR1A register to 0
+ TCCR1A = 0;
+ // set the overflow clock to 0
+ TCNT1 = 0;
+ // set compare match register to desired timer count
+ OCR1A = 2000; // 1ms
+ // turn on CTC mode
+ TCCR1B = (1 << WGM12);
+ // Set 8x prescaler
+ TCCR1B = (TCCR1B & ~(0x07 << CS10)) | (2 << CS10);
+ // enable timer compare interrupt
+ TIMSK1 |= (1 << OCIE1A);
+#endif // ESP8266
+
+ interrupts(); // enable global interrupts
+
+ Serial.println(" done");
+}
+
+
+// turn on power to the motors (make them immobile)
+void motor_engage() {
+ int i;
+ for (i = 0; i < NUM_MOTORS; ++i) {
+ digitalWrite(motors[i].enable_pin, LOW);
+ }
+ /*
+ #if MACHINE_STYLE == ARM6
+ // DM320T drivers want high for enabled
+ digitalWrite(motors[4].enable_pin,HIGH);
+ digitalWrite(motors[5].enable_pin,HIGH);
+ #endif*/
+}
+
+
+// turn off power to the motors (make them move freely)
+void motor_disengage() {
+ int i;
+ for (i = 0; i < NUM_MOTORS; ++i) {
+ digitalWrite(motors[i].enable_pin, HIGH);
+ }/*
+ #if MACHINE_STYLE == ARM6
+ // DM320T drivers want low for disabled
+ digitalWrite(motors[4].enable_pin,LOW);
+ digitalWrite(motors[5].enable_pin,LOW);
+ #endif*/
+}
+
+
+// Change pen state.
+void setPenAngle(int arg0) {
+#if NUM_AXIES>=3
+ if (arg0 < axies[2].limitMin) arg0 = axies[2].limitMin;
+ if (arg0 > axies[2].limitMax) arg0 = axies[2].limitMax;
+
+ axies[2].pos = arg0;
+#endif // NUM_AXIES>=3
+
+#if NUM_SERVOS>0
+// this is commented out because compiler segfault for unknown reasons.
+//#ifndef ESP8266
+// servos[0].write(arg0);
+//#else
+ analogWrite(SERVO0_PIN, arg0);
+//#endif // ESP8266
+#endif // NUM_SERVOS>0
+}
+
+
+
+
+void recalculate_reverse_kernel(Segment *const current, const Segment *next) {
+ if (current == NULL) return;
+
+ const float entry_speed_max2 = current->entry_speed_max;
+ if (current->entry_speed != entry_speed_max2 || (next && next->recalculate_flag) ) {
+ // If nominal length true, max junction speed is guaranteed to be reached. Only compute
+ // for max allowable speed if block is decelerating and nominal length is false.
+ const float new_entry_speed = current->nominal_length_flag
+ ? entry_speed_max2
+ : min( entry_speed_max2, max_speed_allowed(-current->acceleration, (next ? next->entry_speed : MIN_FEEDRATE), current->distance) );
+
+ if (current->entry_speed != new_entry_speed ) {
+ current->entry_speed = new_entry_speed;
+ current->recalculate_flag = true;
+ }
+ }
+}
+
+
+void recalculate_reverse() {
+ if (last_segment == current_segment) return;
+
+ int s = get_prev_segment(last_segment);
+
+ Segment *current, *next = NULL;
+ while (s != current_segment) {
+ current = &line_segments[s];
+
+ recalculate_reverse_kernel(current, next);
+ next = current;
+ s = get_prev_segment(s);
+ }
+}
+
+
+void recalculate_forward_kernel(const Segment *prev, Segment *const current) {
+ if (prev == NULL) return;
+
+ // If the previous block is an acceleration block, but it is not long enough to complete the
+ // full speed change within the block, we need to adjust the entry speed accordingly. Entry
+ // speeds have already been reset, maximized, and reverse planned by reverse planner.
+ // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
+ if (!prev->nominal_length_flag && prev->entry_speed < current->entry_speed) {
+ const float new_entry_speed2 = max_speed_allowed(-prev->acceleration, prev->entry_speed, prev->distance);
+ // Check for junction speed change
+ if (new_entry_speed2 < current->entry_speed) {
+ current->recalculate_flag = true;
+ } else {
+ current->entry_speed = new_entry_speed2;
+ }
+ }
+}
+
+
+void recalculate_forward() {
+ int s = current_segment;
+
+ Segment *previous = NULL, *current;
+ while (s != last_segment) {
+ current = &line_segments[s];
+ recalculate_forward_kernel(previous, current);
+ previous = current;
+ s = get_next_segment(s);
+ }
+}
+
+
+float estimate_acceleration_distance(const float &initial_rate, const float &target_rate, const float &accel) {
+ if (accel == 0) return 0; // accel was 0, set acceleration distance to 0
+ return (sq(target_rate) - sq(initial_rate)) / (accel * 2);
+}
+
+
+int intersection_distance(const float &start_rate, const float &end_rate, const float &accel, const float &distance) {
+ return ( 2.0 * accel * distance - sq(start_rate) + sq(end_rate) ) / (4.0 * accel);
+}
+
+
+void segment_update_trapezoid(Segment *s, const float &entry_factor, const float &exit_factor) {
+ uint32_t intial_rate = ceil(s->nominal_rate * entry_factor);
+ uint32_t final_rate = ceil(s->nominal_rate * exit_factor );
+
+ if (intial_rate < MIN_STEP_RATE) intial_rate = MIN_STEP_RATE;
+ if (final_rate < MIN_STEP_RATE) final_rate = MIN_STEP_RATE;
+
+ const int32_t accel = s->acceleration_steps_per_s2;
+ int32_t accelerate_steps = ceil( estimate_acceleration_distance(intial_rate , s->nominal_rate, accel) );
+ int32_t decelerate_steps = floor( estimate_acceleration_distance(s->nominal_rate, final_rate , -accel) );
+ int32_t plateau_steps = s->steps_total - accelerate_steps - decelerate_steps;
+ if (plateau_steps < 0) {
+ accelerate_steps = ceil( intersection_distance( intial_rate, final_rate, accel, s->steps_total ) );
+ accelerate_steps = min( (uint32_t)max( accelerate_steps, 0 ), s->steps_total );
+ plateau_steps = 0;
+ }
+ CRITICAL_SECTION_START
+ /*
+ decelerate_steps = s->steps_total - plateau_steps - accelerate_steps;
+ Serial.print("t entry_factor="); Serial.print(entry_factor);
+ Serial.print(" exit_factor="); Serial.print(exit_factor);
+ Serial.print(" accel="); Serial.print(accel);
+ Serial.print(" intial_rate="); Serial.print(intial_rate);
+ Serial.print(" nominal_rate="); Serial.print(s->nominal_rate);
+ Serial.print(" final_rate="); Serial.print(final_rate);
+ Serial.print(" steps_total="); Serial.print(s->steps_total);
+ Serial.print(" accelerate_steps="); Serial.print(accelerate_steps);
+ Serial.print(" plateau_steps="); Serial.print(plateau_steps);
+ Serial.print(" decelerate_steps="); Serial.print(decelerate_steps);
+ Serial.println();
+ */
+ if (!s->busy) {
+ s->accel_until = accelerate_steps;
+ s->decel_after = accelerate_steps + plateau_steps;
+ s->initial_rate = intial_rate;
+ s->final_rate = final_rate;
+ }
+ CRITICAL_SECTION_END
+}
+
+
+void recalculate_trapezoids() {
+ int s = current_segment;
+ Segment *current = NULL;
+ Segment *next = NULL;
+
+ float current_entry_speed = 0, next_entry_speed = 0;
+
+ while (s != last_segment) {
+ next = &line_segments[s];
+ next_entry_speed = next->entry_speed;
+ if (current) {
+ // Recalculate if current block entry or exit junction speed has changed.
+ if ( current->recalculate_flag || next->recalculate_flag ) {
+ if (!current->busy) {
+ // NOTE: Entry and exit factors always > 0 by all previous logic operations.
+ const float inom = 1.0 / current->nominal_speed;
+ segment_update_trapezoid(current, current_entry_speed * inom, next_entry_speed * inom);
+ }
+ }
+ current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
+ }
+ s = get_next_segment(s);
+ current_entry_speed = next_entry_speed;
+ current = next;
+ }
+
+ // Last/newest block in buffer. Make sure the last block always ends motion.
+ if (next != NULL) {
+ const float inom = 1.0 / next->nominal_speed;
+ segment_update_trapezoid(next, next_entry_speed * inom, MIN_FEEDRATE * inom);
+ next->recalculate_flag = false;
+ }
+}
+
+
+void describe_segments() {
+ CRITICAL_SECTION_START
+ /**/
+ Serial.println("A = index");
+ Serial.println("B = distance");
+ Serial.println("C = acceleration");
+
+ Serial.println("D = entry_speed");
+ Serial.println("E = nominal_speed");
+ Serial.println("F = entry_speed_max");
+
+ Serial.println("G = entry rate");
+ Serial.println("H = nominal rate");
+ Serial.println("I = exit rate");
+
+ Serial.println("J = accel_until");
+ Serial.println("K = coast steps");
+ Serial.println("L = decel steps");
+
+ Serial.println("O = nominal?");
+ Serial.println("P = recalculate?");
+ Serial.println("Q = busy?");/**/
+ Serial.println("\nA\tB\tC\tD\tE\tF\t[G\tH\tI]\t[J\tK\tL]\tO\tP\tQ");
+ Serial.println("---------------------------------------------------------------------------------------------------------------------------");
+
+ int s = current_segment;
+ while (s != last_segment) {
+ Segment *next = &line_segments[s];
+ int coast = next->decel_after - next->accel_until;
+ int decel = next->steps_total - next->decel_after;
+ Serial.print(s);
+ Serial.print(F("\t")); Serial.print(next->distance);
+ Serial.print(F("\t")); Serial.print(next->acceleration);
+
+ Serial.print(F("\t")); Serial.print(next->entry_speed);
+ Serial.print(F("\t")); Serial.print(next->nominal_speed);
+ Serial.print(F("\t")); Serial.print(next->entry_speed_max);
+
+ Serial.print(F("\t")); Serial.print(next->initial_rate);
+ Serial.print(F("\t")); Serial.print(next->nominal_rate);
+ Serial.print(F("\t")); Serial.print(next->final_rate);
+
+ Serial.print(F("\t")); Serial.print(next->accel_until);
+ Serial.print(F("\t")); Serial.print(coast);
+ Serial.print(F("\t")); Serial.print(decel);
+ //Serial.print(F("\t")); Serial.print(next->steps_total);
+ //Serial.print(F("\t")); Serial.print(next->steps_taken);
+
+ Serial.print(F("\t")); Serial.print(next->nominal_length_flag != 0 ? 'Y' : 'N');
+ Serial.print(F("\t")); Serial.print(next->recalculate_flag != 0 ? 'Y' : 'N');
+ Serial.print(F("\t")); Serial.print(next->busy != 0 ? 'Y' : 'N');
+ Serial.println();
+ s = get_next_segment(s);
+ }
+ CRITICAL_SECTION_END
+}
+
+
+void recalculate_acceleration() {
+ recalculate_reverse();
+ recalculate_forward();
+ recalculate_trapezoids();
+
+ //Serial.println("**FINISHED**");
+ //describe_segments();
+}
+
+
+void motor_set_step_count(long *a) {
+ wait_for_empty_segment_buffer();
+
+ for (int i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ previous_speed[i] = 0;
+ }
+
+ Segment &old_seg = line_segments[get_prev_segment(last_segment)];
+ old_seg.a[0].step_count = a[0];
+#if NUM_MOTORS>1
+ old_seg.a[1].step_count = a[1];
+#endif
+#if NUM_MOTORS>2
+ old_seg.a[2].step_count = a[2];
+#endif
+#if NUM_MOTORS>3
+ old_seg.a[3].step_count = a[3];
+#endif
+#if NUM_MOTORS>4
+ old_seg.a[4].step_count = a[4];
+#endif
+#if NUM_MOTORS>5
+ old_seg.a[5].step_count = a[5];
+#endif
+#if NUM_SERVOS>0
+ old_seg.a[NUM_MOTORS].step_count = a[NUM_MOTORS];
+#endif
+
+ global_steps_0 = 0;
+#if NUM_MOTORS>1
+ global_steps_1 = 0;
+#endif
+#if NUM_MOTORS>2
+ global_steps_2 = 0;
+#endif
+#if NUM_MOTORS>3
+ global_steps_3 = 0;
+#endif
+#if NUM_MOTORS>4
+ global_steps_4 = 0;
+#endif
+#if NUM_MOTORS>5
+ global_steps_5 = 0;
+#endif
+}
+
+
+/**
+ Step one motor one time in the currently set direction.
+ @input newx the destination x position
+ @input newy the destination y position
+ **/
+void motor_onestep(int motor) {
+#ifdef VERBOSE
+ Serial.print(motorNames[motor]);
+#endif
+
+ digitalWrite(motors[motor].step_pin, HIGH);
+ digitalWrite(motors[motor].step_pin, LOW);
+}
+
+
+/**
+ Set the clock 2 timer frequency.
+ @input desired_freq_hz the desired frequency
+ Different clock sources can be selected for each timer independently.
+ To calculate the timer frequency (for example 2Hz using timer1) you will need:
+*/
+FORCE_INLINE unsigned short calc_timer(uint32_t desired_freq_hz, uint8_t*loops) {
+ if ( desired_freq_hz > CLOCK_MAX_STEP_FREQUENCY ) desired_freq_hz = CLOCK_MAX_STEP_FREQUENCY;
+ if ( desired_freq_hz < CLOCK_MIN_STEP_FREQUENCY ) desired_freq_hz = CLOCK_MIN_STEP_FREQUENCY;
+ //desired_freq_hz-=CLOCK_MIN_STEP_FREQUENCY;
+
+ uint8_t step_multiplier = 1;
+ if ( desired_freq_hz > 20000 ) {
+ step_multiplier = 4;
+ desired_freq_hz >>= 2;
+ } else if ( desired_freq_hz > 10000 ) {
+ step_multiplier = 2;
+ desired_freq_hz >>= 1;
+ }
+ *loops = step_multiplier;
+
+ long counter_value = ( CLOCK_FREQ >> 3 ) / desired_freq_hz;
+ if ( counter_value >= MAX_COUNTER ) {
+ counter_value = MAX_COUNTER - 1;
+ } else if ( counter_value < 100 ) {
+ counter_value = 100;
+ }
+
+ return counter_value;
+}
+
+
+#define A(CODE) " " CODE "\n\t"
+
+// intRes = longIn1 * longIn2 >> 24
+// uses:
+// A[tmp] to store 0
+// B[tmp] to store bits 16-23 of the 48bit result. The top bit is used to round the two byte result.
+// note that the lower two bytes and the upper byte of the 48bit result are not calculated.
+// this can cause the result to be out by one as the lower bytes may cause carries into the upper ones.
+// B A are bits 24-39 and are the returned value
+// C B A is longIn1
+// D C B A is longIn2
+//
+static FORCE_INLINE uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) {
+#ifdef ESP8266
+ uint16_t intRes = longIn1 * longIn2 >> 24;
+#else // ESP8266
+ register uint8_t tmp1;
+ register uint8_t tmp2;
+ register uint16_t intRes;
+ __asm__ __volatile__(
+ A("clr %[tmp1]")
+ A("mul %A[longIn1], %B[longIn2]")
+ A("mov %[tmp2], r1")
+ A("mul %B[longIn1], %C[longIn2]")
+ A("movw %A[intRes], r0")
+ A("mul %C[longIn1], %C[longIn2]")
+ A("add %B[intRes], r0")
+ A("mul %C[longIn1], %B[longIn2]")
+ A("add %A[intRes], r0")
+ A("adc %B[intRes], r1")
+ A("mul %A[longIn1], %C[longIn2]")
+ A("add %[tmp2], r0")
+ A("adc %A[intRes], r1")
+ A("adc %B[intRes], %[tmp1]")
+ A("mul %B[longIn1], %B[longIn2]")
+ A("add %[tmp2], r0")
+ A("adc %A[intRes], r1")
+ A("adc %B[intRes], %[tmp1]")
+ A("mul %C[longIn1], %A[longIn2]")
+ A("add %[tmp2], r0")
+ A("adc %A[intRes], r1")
+ A("adc %B[intRes], %[tmp1]")
+ A("mul %B[longIn1], %A[longIn2]")
+ A("add %[tmp2], r1")
+ A("adc %A[intRes], %[tmp1]")
+ A("adc %B[intRes], %[tmp1]")
+ A("lsr %[tmp2]")
+ A("adc %A[intRes], %[tmp1]")
+ A("adc %B[intRes], %[tmp1]")
+ A("mul %D[longIn2], %A[longIn1]")
+ A("add %A[intRes], r0")
+ A("adc %B[intRes], r1")
+ A("mul %D[longIn2], %B[longIn1]")
+ A("add %B[intRes], r0")
+ A("clr r1")
+ : [intRes] "=&r" (intRes),
+ [tmp1] "=&r" (tmp1),
+ [tmp2] "=&r" (tmp2)
+ : [longIn1] "d" (longIn1),
+ [longIn2] "d" (longIn2)
+ : "cc"
+ );
+#endif // ESP8266
+ return intRes;
+}
+
+/**
+ Process all line segments in the ring buffer. Uses bresenham's line algorithm to move all motors.
+*/
+
+#ifdef ESP8266
+void itr() {
+#else
+ISR(TIMER1_COMPA_vect) {
+#endif
+ // segment buffer empty? do nothing
+ if ( working_seg == NULL ) {
+ working_seg = get_current_segment();
+
+ if ( working_seg != NULL ) {
+ // New segment!
+ working_seg->busy = true;
+
+ // set the direction pins
+ digitalWrite( MOTOR_0_DIR_PIN, working_seg->a[0].dir );
+ global_step_dir_0 = (working_seg->a[0].dir == HIGH) ? 1 : -1;
+
+#if NUM_MOTORS>1
+ digitalWrite( MOTOR_1_DIR_PIN, working_seg->a[1].dir );
+ global_step_dir_1 = (working_seg->a[1].dir == HIGH) ? 1 : -1;
+#endif
+#if NUM_MOTORS>2
+ digitalWrite( MOTOR_2_DIR_PIN, working_seg->a[2].dir );
+ global_step_dir_2 = (working_seg->a[2].dir == HIGH) ? 1 : -1;
+#endif
+#if NUM_MOTORS>3
+ digitalWrite( MOTOR_3_DIR_PIN, working_seg->a[3].dir );
+ global_step_dir_3 = (working_seg->a[3].dir == HIGH) ? 1 : -1;
+#endif
+#if NUM_MOTORS>4
+ digitalWrite( MOTOR_4_DIR_PIN, working_seg->a[4].dir );
+ global_step_dir_4 = (working_seg->a[4].dir == HIGH) ? 1 : -1;
+#endif
+#if NUM_MOTORS>5
+ digitalWrite( MOTOR_5_DIR_PIN, working_seg->a[5].dir );
+ global_step_dir_5 = (working_seg->a[5].dir == HIGH) ? 1 : -1;
+#endif
+
+#if NUM_SERVOS>0
+#ifdef ESP8266
+ analogWrite(SERVO0_PIN, working_seg->a[NUM_MOTORS].step_count);
+#else
+ servos[0].write(working_seg->a[NUM_MOTORS].step_count);
+#endif // ESP8266
+#endif // NUM_SERVOS>0
+
+ start_feed_rate = working_seg->initial_rate;
+ end_feed_rate = working_seg->final_rate;
+ current_feed_rate = start_feed_rate;
+ current_acceleration = working_seg->acceleration_rate;
+ accel_until = working_seg->accel_until;
+ decel_after = working_seg->decel_after;
+ time_accelerating = 0;
+ time_decelerating = 0;
+ isr_nominal_rate = 0;
+
+ // defererencing some data so the loop runs faster.
+ steps_total = working_seg->steps_total;
+ steps_taken = 0;
+ delta0 = working_seg->a[0].absdelta; over0 = -(steps_total >> 1);
+#if NUM_MOTORS>1
+ delta1 = working_seg->a[1].absdelta; over1 = -(steps_total >> 1);
+#endif
+#if NUM_MOTORS>2
+ delta2 = working_seg->a[2].absdelta; over2 = -(steps_total >> 1);
+#endif
+#if NUM_MOTORS>3
+ delta3 = working_seg->a[3].absdelta; over3 = -(steps_total >> 1);
+#endif
+#if NUM_MOTORS>4
+ delta4 = working_seg->a[4].absdelta; over4 = -(steps_total >> 1);
+#endif
+#if NUM_MOTORS>5
+ delta5 = working_seg->a[5].absdelta; over5 = -(steps_total >> 1);
+#endif
+ return;
+ } else {
+ CLOCK_ADJUST(2000); // wait 1ms
+ return;
+ }
+ }
+
+ if ( working_seg != NULL ) {
+ // move each axis
+ for (uint8_t i = 0; i < isr_step_multiplier; ++i) {
+ over0 += delta0;
+ if (over0 > 0) digitalWrite(MOTOR_0_STEP_PIN, LOW);
+#if NUM_MOTORS>1
+ over1 += delta1;
+ if (over1 > 0) digitalWrite(MOTOR_1_STEP_PIN, LOW);
+#endif
+#if NUM_MOTORS>2
+ over2 += delta2;
+ if (over2 > 0) digitalWrite(MOTOR_2_STEP_PIN, LOW);
+#endif
+#if NUM_MOTORS>3
+ over3 += delta3;
+ if (over3 > 0) digitalWrite(MOTOR_3_STEP_PIN, LOW);
+#endif
+#if NUM_MOTORS>4
+ over4 += delta4;
+ if (over4 > 0) digitalWrite(MOTOR_4_STEP_PIN, LOW);
+#endif
+#if NUM_MOTORS>5
+ over5 += delta5;
+ if (over5 > 0) digitalWrite(MOTOR_5_STEP_PIN, LOW);
+#endif
+ // now that the pins have had a moment to settle, do the second half of the steps.
+ // M0
+ if (over0 > 0) {
+ over0 -= steps_total;
+ global_steps_0 += global_step_dir_0;
+ digitalWrite(MOTOR_0_STEP_PIN, HIGH);
+ }
+#if NUM_MOTORS>1
+ // M1
+ if (over1 > 0) {
+ over1 -= steps_total;
+ global_steps_1 += global_step_dir_1;
+ digitalWrite(MOTOR_1_STEP_PIN, HIGH);
+ }
+#endif
+#if NUM_MOTORS>2
+ // M2
+ if (over2 > 0) {
+ over2 -= steps_total;
+ global_steps_2 += global_step_dir_2;
+ digitalWrite(MOTOR_2_STEP_PIN, HIGH);
+ }
+#endif
+#if NUM_MOTORS>3
+ // M3
+ if (over3 > 0) {
+ over3 -= steps_total;
+ global_steps_3 += global_step_dir_3;
+ digitalWrite(MOTOR_3_STEP_PIN, HIGH);
+ }
+#endif
+#if NUM_MOTORS>4
+ // M4
+ if (over4 > 0) {
+ over4 -= steps_total;
+ global_steps_4 += global_step_dir_4;
+ digitalWrite(MOTOR_4_STEP_PIN, HIGH);
+ }
+#endif
+#if NUM_MOTORS>5
+ // M5
+ if (over5 > 0) {
+ over5 -= steps_total;
+ global_steps_5 += global_step_dir_5;
+ digitalWrite(MOTOR_5_STEP_PIN, HIGH);
+ }
+#endif
+
+ // make a step
+ steps_taken++;
+ if (steps_taken >= steps_total) break;
+ }
+
+
+ // Is this segment done?
+ if ( steps_taken >= steps_total ) {
+ // Move on to next segment without wasting an interrupt tick.
+ working_seg = NULL;
+ current_segment = get_next_segment(current_segment);
+ return;
+ }
+
+ // accel
+ uint32_t interval;
+ if ( steps_taken <= accel_until ) {
+ current_feed_rate = start_feed_rate + MultiU24X32toH16( time_accelerating, current_acceleration );
+ if (current_feed_rate > working_seg->nominal_rate) {
+ current_feed_rate = working_seg->nominal_rate;
+ }
+ interval = calc_timer(current_feed_rate, &isr_step_multiplier);
+ time_accelerating += interval;
+ CLOCK_ADJUST(interval);
+ /*
+ Serial.print("A\t");
+ Serial.print(current_feed_rate);
+ Serial.print("\t");
+ Serial.println(isr_step_multiplier);//*/
+ /*
+ Serial.print("A >> "); Serial.print(interval);
+ Serial.print("\t"); Serial.print(isr_step_multiplier);
+ Serial.print("\t"); Serial.print(current_feed_rate);
+ Serial.print(" = "); Serial.print(start_feed_rate);
+ Serial.print(" + "); Serial.print(current_acceleration);
+ Serial.print(" * "); Serial.print(time_accelerating);
+ Serial.println();//*/
+ } else if ( steps_taken > decel_after ) {
+ uint32_t end_feed_rate = current_feed_rate - MultiU24X32toH16( time_decelerating, current_acceleration );
+ if ( end_feed_rate < working_seg->final_rate ) {
+ end_feed_rate = working_seg->final_rate;
+ }
+ interval = calc_timer(end_feed_rate, &isr_step_multiplier);
+ time_decelerating += interval;
+ CLOCK_ADJUST(interval);
+ /*
+ Serial.print("D\t");
+ Serial.print(end_feed_rate);
+ Serial.print("\t");
+ Serial.println(isr_step_multiplier);//*/
+ /*
+ Serial.print("D >> "); Serial.print(interval);
+ Serial.print("\t"); Serial.print(isr_step_multiplier);
+ Serial.print("\t"); Serial.print(end_feed_rate);
+ Serial.print(" = "); Serial.print(current_feed_rate);
+ Serial.print(" - "); Serial.print(current_acceleration);
+ Serial.print(" * "); Serial.print(time_decelerating);
+ Serial.println();//*/
+ } else {
+ if (isr_nominal_rate == 0) {
+ isr_nominal_rate = calc_timer(working_seg->nominal_rate, &isr_step_multiplier);
+ }
+ CLOCK_ADJUST(isr_nominal_rate);
+ /*
+ Serial.print("C\t");
+ Serial.print(working_seg->nominal_rate);
+ Serial.print("\t");
+ Serial.println(isr_step_multiplier);//*/
+ /*
+ Serial.print("C >> "); Serial.println(working_seg->nominal_rate);
+ //Serial.print("\t"); Serial.print(interval);
+ //Serial.print("\t"); Serial.print(isr_step_multiplier);
+ Serial.print("\t"); Serial.print(current_feed_rate);
+ Serial.println();//*/
+ }
+#ifndef ESP8266
+ OCR1A = (OCR1A < (TCNT1 + 16)) ? (TCNT1 + 16) : OCR1A;
+#endif // ESP8266
+ }
+}
+
+
+/**
+ @return 1 if buffer is full, 0 if it is not.
+*/
+char segment_buffer_full() {
+ int next_segment = get_next_segment(last_segment);
+ return (next_segment == current_segment);
+}
+
+
+/**
+ Translate the XYZ through the IK to get the number of motor steps and move the motors.
+ Uses bresenham's line algorithm to move both motors
+ @input pos NUM_AXIES floats describing destination coordinates
+ @input new_feed_rate speed to travel along arc
+*/
+void motor_line(const float * const target_position, float &fr_mm_s) {
+ long steps[NUM_MOTORS + NUM_SERVOS];
+
+ // convert from the cartesian position to the motor steps
+ IK(target_position, steps);
+
+ float distance_mm = 0;
+
+ // record the new target position & feed rate for the next movement.
+ int i;
+ for (i = 0; i < NUM_AXIES; ++i) {
+ distance_mm += sq(target_position[i] - axies[i].pos);
+ axies[i].pos = target_position[i];
+ }
+ distance_mm = sqrt( distance_mm );
+ feed_rate = fr_mm_s;
+
+ // get the next available spot in the segment buffer
+ int next_segment = get_next_segment(last_segment);
+ while ( next_segment == current_segment ) {
+ // the segment buffer is full, we are way ahead of the motion system. wait here.
+ delay(1);
+ }
+
+ int prev_segment = get_prev_segment(last_segment);
+ Segment &new_seg = line_segments[last_segment];
+ Segment &old_seg = line_segments[prev_segment];
+
+ // use LCD to adjust speed while drawing
+#ifdef HAS_LCD
+ fr_mm_s *= (float)speed_adjust * 0.01f;
+#endif
+
+ new_seg.busy = false;
+ new_seg.distance = distance_mm;
+ float inverse_distance_mm = 1.0 / new_seg.distance;
+ float inverse_secs = fr_mm_s * inverse_distance_mm;
+
+ // The axis that has the most steps will control the overall acceleration as per bresenham's algorithm.
+ new_seg.steps_total = 0;
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ new_seg.a[i].step_count = steps[i];
+ new_seg.a[i].delta_steps = steps[i] - old_seg.a[i].step_count;
+ new_seg.a[i].delta_mm = new_seg.a[i].delta_steps * THREAD_PER_STEP;
+ new_seg.a[i].dir = ( new_seg.a[i].delta_steps < 0 ? HIGH : LOW );
+ new_seg.a[i].absdelta = abs(new_seg.a[i].delta_steps);
+ if ( new_seg.steps_total < new_seg.a[i].absdelta ) {
+ new_seg.steps_total = new_seg.a[i].absdelta;
+ }
+ }
+
+ // No steps? No work! Stop now.
+ if ( new_seg.steps_total == 0 ) return;
+
+ new_seg.nominal_speed = new_seg.distance * inverse_secs;
+ new_seg.nominal_rate = ceil(new_seg.steps_total * inverse_secs);
+
+ // Calculate the the speed limit for each axis
+ float current_speed[NUM_MOTORS + NUM_SERVOS], speed_factor = 1.0;
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ current_speed[i] = new_seg.a[i].delta_mm * inverse_secs;
+ const float cs = fabs(current_speed[i]);
+ if (cs > max_feedrate_mm_s[i]) speed_factor = min (speed_factor, max_feedrate_mm_s[i] / cs);
+ //if (cs > MAX_FEEDRATE) speed_factor = min (speed_factor, MAX_FEEDRATE / cs);
+ }
+
+ if (speed_factor < 1.0) {
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ current_speed[i] *= speed_factor;
+ }
+ new_seg.nominal_speed *= speed_factor;
+ new_seg.nominal_rate *= speed_factor;
+ }
+
+ const float steps_per_mm = new_seg.steps_total * inverse_distance_mm;
+ uint32_t accel = ceil( acceleration * steps_per_mm );
+
+ const float max_acceleration_steps_per_s2 = acceleration * steps_per_mm;
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ if (new_seg.a[i].delta_steps && max_acceleration_steps_per_s2 < accel) {
+ const float comp = (float)max_acceleration_steps_per_s2 * (float)new_seg.steps_total;
+ if ((float)accel * (float)new_seg.a[i].delta_steps > comp ) {
+ accel = comp / (float)new_seg.a[i].delta_steps;
+ }
+ }
+ }
+ new_seg.acceleration_steps_per_s2 = accel;
+ new_seg.acceleration = accel / steps_per_mm;
+ new_seg.acceleration_rate = (uint32_t)(accel * (4096.0f * 4096.0f / (TIMER_RATE)));
+ new_seg.steps_taken = 0;
+
+ // TODO explain this
+ float safe_speed = new_seg.nominal_speed;
+ char limited = 0;
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ const float jerk = fabs(current_speed[i]), maxj = max_xy_jerk;
+ if (jerk > maxj) {
+ if (limited) {
+ // TODO explain this
+ const float mjerk = maxj * new_seg.nominal_speed;
+ if (jerk * safe_speed > mjerk) safe_speed = mjerk / jerk;
+ } else {
+ ++limited;
+ safe_speed *= maxj / jerk;
+ }
+ }
+ }
+
+ // what is the maximum starting speed for this segment?
+ float vmax_junction = MIN_FEEDRATE;
+
+ int movesQueued = movesPlanned();
+ if (movesQueued > 0 && previous_safe_speed > 0.0001) {
+ // Estimate a maximum velocity allowed at a joint of two successive segments.
+ // If this maximum velocity allowed is lower than the minimum of the entry / exit safe velocities,
+ // then the machine is not coasting anymore and the safe entry / exit velocities shall be used.
+
+ // The junction velocity will be shared between successive segments. Limit the junction velocity to their minimum.
+ // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
+ vmax_junction = min(new_seg.nominal_speed, previous_nominal_speed);
+ const float smaller_speed_factor = vmax_junction / previous_nominal_speed;
+ // Factor to multiply the previous / current nominal velocities to get componentwise limited velocities.
+ float v_factor = 1.0f;
+ limited = 0;
+ // Now limit the jerk in all axes.
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ // Limit an axis. We have to differentiate: coasting, reversal of an axis, full stop.
+ float v_exit = previous_speed[i] * smaller_speed_factor;
+ float v_entry = current_speed[i];
+ if (limited) {
+ v_exit *= v_factor;
+ v_entry *= v_factor;
+ }
+
+ // Calculate jerk depending on whether the axis is coasting in the same direction or reversing.
+ const float jerk = (v_exit > v_entry)
+ ? // coasting axis reversal
+ ( (v_entry > 0 || v_exit < 0) ? (v_exit - v_entry) : max(v_exit, -v_entry) )
+ : // v_exit <= v_entry coasting axis reversal
+ ( (v_entry < 0 || v_exit > 0) ? (v_entry - v_exit) : max(-v_exit, v_entry) );
+
+ if (jerk > max_xy_jerk) {
+ v_factor *= max_xy_jerk / jerk;
+ ++limited;
+ }
+ }
+ if (limited) vmax_junction *= v_factor;
+ // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
+ // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
+ const float vmax_junction_threshold = vmax_junction * 0.99f;
+ if (previous_safe_speed > vmax_junction_threshold && safe_speed > vmax_junction_threshold) {
+ // Not coasting. The machine will stop and start the movements anyway,
+ // better to start the segment from start.
+ //SBI(new_seg.flag, BLOCK_BIT_START_FROM_FULL_HALT);
+ vmax_junction = safe_speed;
+ }
+ }
+
+ float allowable_speed = max_speed_allowed(-new_seg.acceleration, MIN_FEEDRATE, new_seg.distance);
+
+#if NUM_SERVOS>0
+ // come to a stop for entering or exiting a Z move
+ //if( new_seg.a[NUM_SERVOS].delta_steps != 0 || old_seg.a[NUM_SERVOS].delta_steps != 0 ) allowable_speed = MIN_FEEDRATE;
+#endif
+
+ new_seg.entry_speed_max = vmax_junction;
+ new_seg.entry_speed = min(vmax_junction, allowable_speed);
+ new_seg.nominal_length_flag = ( allowable_speed >= new_seg.nominal_speed );
+ new_seg.recalculate_flag = true;
+
+ previous_nominal_speed = new_seg.nominal_speed;
+ previous_safe_speed = safe_speed;
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ previous_speed[i] = current_speed[i];
+ }
+
+ // when should we accelerate and decelerate in this segment?
+ segment_update_trapezoid(&new_seg, new_seg.entry_speed / new_seg.nominal_speed, (float)MIN_FEEDRATE / new_seg.nominal_speed);
+
+ if (current_segment == last_segment ) {
+ first_segment_delay = BLOCK_DELAY_FOR_1ST_MOVE;
+ }
+ last_segment = next_segment;
+
+ recalculate_acceleration();
+ /*
+ Serial.print("distance="); Serial.println(new_seg.distance);
+ Serial.print("acceleration original="); Serial.println(acceleration);
+ Serial.print("nominal_speed="); Serial.println(new_seg.nominal_speed);
+
+ Serial.print("inverse_distance_mm="); Serial.println(inverse_distance_mm);
+ Serial.print("inverse_secs="); Serial.println(inverse_secs);
+ Serial.print("nominal_rate="); Serial.println(new_seg.nominal_rate);
+ Serial.print("delta_mm=");
+ for (i = 0; i < NUM_MOTORS + NUM_SERVOS; ++i) {
+ if (i > 0) Serial.print(", ");
+ Serial.print(new_seg.a[i].delta_mm);
+ }
+ Serial.println();
+ Serial.print("speed_factor="); Serial.println(speed_factor);
+ Serial.print("steps_per_mm="); Serial.println(steps_per_mm);
+ Serial.print("accel="); Serial.println(accel);
+ Serial.print("acceleration_steps_per_s2="); Serial.println(new_seg.acceleration_steps_per_s2);
+ Serial.print("acceleration="); Serial.println(new_seg.acceleration);
+ Serial.print("limited="); Serial.println(limited, DEC);
+ Serial.print("nominal_speed="); Serial.println(new_seg.nominal_speed);
+ Serial.print("vmax_junction="); Serial.println(vmax_junction);
+ Serial.print("allowable_speed="); Serial.println(allowable_speed);
+ Serial.print("safe_speed="); Serial.println(safe_speed);
+ //*/
+}
+
+
+void wait_for_empty_segment_buffer() {
+ while ( current_segment != last_segment );
+}
diff --git a/motor.h b/motor.h
new file mode 100644
index 0000000..060a35b
--- /dev/null
+++ b/motor.h
@@ -0,0 +1,84 @@
+#ifndef MOTOR_H
+#define MOTOR_H
+//------------------------------------------------------------------------------
+// Makelangelo - firmware for various robot kinematic models
+// dan@marginallycelver.com 2013-12-26
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+//------------------------------------------------------------------------------
+
+#include
+
+//------------------------------------------------------------------------------
+// CONSTANTS
+//------------------------------------------------------------------------------
+
+
+typedef struct {
+ int step_pin;
+ int dir_pin;
+ int enable_pin;
+ int limit_switch_pin;
+} Motor;
+
+
+// for line()
+typedef struct {
+ int32_t step_count; // current motor position, in steps.
+ int32_t delta_steps; // steps
+ int32_t delta_mm; // mm
+ uint32_t absdelta;
+ int dir;
+} SegmentAxis;
+
+
+typedef struct {
+ SegmentAxis a[NUM_MOTORS+NUM_SERVOS];
+
+ float distance; // mm
+ float nominal_speed; // mm/s
+ float entry_speed; // mm/s
+ float entry_speed_max; // mm/s
+ float acceleration; // mm/sec^2
+
+ uint32_t steps_total; // steps
+ uint32_t steps_taken; // steps
+ uint32_t accel_until; // steps
+ uint32_t decel_after; // steps
+
+ uint32_t nominal_rate; // steps/s
+ uint32_t initial_rate; // steps/s
+ uint32_t final_rate; // steps/s
+ uint32_t acceleration_steps_per_s2; // steps/s^2
+ uint32_t acceleration_rate; //
+
+ char nominal_length_flag;
+ char recalculate_flag;
+ char busy;
+} Segment;
+
+
+//------------------------------------------------------------------------------
+// GLOBALS
+//------------------------------------------------------------------------------
+
+extern Segment line_segments[MAX_SEGMENTS];
+extern Segment *working_seg;
+extern volatile int current_segment;
+extern volatile int last_segment;
+extern Motor motors[NUM_MOTORS+NUM_SERVOS];
+extern const char *AxisNames;
+extern const char *MotorNames;
+extern float maxFeedRate[NUM_MOTORS];
+extern float max_xy_jerk;
+extern float max_feedrate_mm_s[NUM_MOTORS+NUM_SERVOS];
+
+extern void motor_set_step_count(long *a);
+extern void wait_for_empty_segment_buffer();
+extern char segment_buffer_full();
+extern void motor_line(const float * const target_position,float &fr_mm_s);
+extern void motor_engage();
+extern void motor_disengage();
+extern void motor_setup();
+extern void setPenAngle(int arg0);
+
+#endif // MOTOR_H
diff --git a/motor.ino b/motor.ino
deleted file mode 100644
index a83be7a..0000000
--- a/motor.ino
+++ /dev/null
@@ -1,926 +0,0 @@
-//------------------------------------------------------------------------------
-// Makelangelo - firmware for various robot kinematic models
-// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
-//------------------------------------------------------------------------------
-
-
-//------------------------------------------------------------------------------
-// INCLUDES
-//------------------------------------------------------------------------------
-#include "MServo.h"
-
-
-//------------------------------------------------------------------------------
-// GLOBALS
-//------------------------------------------------------------------------------
-
-Motor motors[NUM_MOTORS+NUM_SERVOS];
-Servo servos[NUM_SERVOS];
-
-Segment line_segments[MAX_SEGMENTS];
-Segment *working_seg = NULL;
-volatile int current_segment=0;
-volatile int last_segment=0;
-int step_multiplier, nominal_step_multiplier;
-unsigned short nominal_OCR1A;
-
-// used by timer1 to optimize interrupt inner loop
-int steps_total;
-int steps_taken;
-int accel_until,decel_after;
-long current_feed_rate;
-long current_acceleration;
-long old_feed_rate=0;
-long start_feed_rate,end_feed_rate;
-long time_accelerating,time_decelerating;
-float max_xy_jerk = MAX_JERK;
-
-int delta0;
-int over0;
-long global_steps_0;
-int global_step_dir_0;
-#if NUM_MOTORS>1
-int delta1;
-int over1;
-long global_steps_1;
-int global_step_dir_1;
-#endif
-#if NUM_MOTORS>2
-int delta2;
-int over2;
-long global_steps_2;
-int global_step_dir_2;
-#endif
-#if NUM_MOTORS>3
-int delta3;
-int over3;
-long global_steps_3;
-int global_step_dir_3;
-#endif
-#if NUM_MOTORS>4
-int delta4;
-int over4;
-long global_steps_4;
-int global_step_dir_4;
-#endif
-#if NUM_MOTORS>5
-int delta5;
-int over5;
-long global_steps_5;
-int global_step_dir_5;
-#endif
-
-
-const char *MotorNames="LRUVWT";
-const char *AxisNames="XYZUVWT";
-float maxFeedRate[NUM_MOTORS];
-
-
-//------------------------------------------------------------------------------
-// METHODS
-//------------------------------------------------------------------------------
-
-
-// for reasons I don't understand... if i put this method in the .h file i get compile errors.
-// so I put it here, which forces the externs.
-FORCE_INLINE Segment *segment_get_working() {
- if(current_segment == last_segment ) return NULL;
- working_seg = &line_segments[current_segment];
- working_seg->busy=true;
- return working_seg;
-}
-
-
-FORCE_INLINE int get_next_segment(int i) {
- return SEGMOD( i + 1 );
-}
-
-
-FORCE_INLINE int get_prev_segment(int i) {
- return SEGMOD( i - 1 );
-}
-
-/**
- * Calculate the maximum allowable speed at this point, in order
- * to reach 'target_velocity' using 'acceleration' within a given
- * 'distance'.
- * @param acc acceleration
- * @param target_velocity
- * @param distance
- */
-float max_speed_allowed(float acc, float target_velocity, float distance) {
- return sqrt( target_velocity*target_velocity - 2 * acc * distance );
-}
-
-
-/**
- * set up the pins for each motor
- */
-void motor_setup() {
- motors[0].step_pin =MOTOR_0_STEP_PIN;
- motors[0].dir_pin =MOTOR_0_DIR_PIN;
- motors[0].enable_pin =MOTOR_0_ENABLE_PIN;
- motors[0].limit_switch_pin=MOTOR_0_LIMIT_SWITCH_PIN;
-#if NUM_MOTORS>1
- motors[1].step_pin =MOTOR_1_STEP_PIN;
- motors[1].dir_pin =MOTOR_1_DIR_PIN;
- motors[1].enable_pin =MOTOR_1_ENABLE_PIN;
- motors[1].limit_switch_pin=MOTOR_1_LIMIT_SWITCH_PIN;
-#endif
-#if NUM_MOTORS>2
- motors[2].step_pin =MOTOR_2_STEP_PIN;
- motors[2].dir_pin =MOTOR_2_DIR_PIN;
- motors[2].enable_pin =MOTOR_2_ENABLE_PIN;
- motors[2].limit_switch_pin=MOTOR_2_LIMIT_SWITCH_PIN;
-#endif
-#if NUM_MOTORS>3
- motors[3].step_pin =MOTOR_3_STEP_PIN;
- motors[3].dir_pin =MOTOR_3_DIR_PIN;
- motors[3].enable_pin =MOTOR_3_ENABLE_PIN;
- motors[3].limit_switch_pin=MOTOR_3_LIMIT_SWITCH_PIN;
-#endif
-#if NUM_MOTORS>4
- motors[4].step_pin =MOTOR_4_STEP_PIN;
- motors[4].dir_pin =MOTOR_4_DIR_PIN;
- motors[4].enable_pin =MOTOR_4_ENABLE_PIN;
- motors[4].limit_switch_pin=MOTOR_4_LIMIT_SWITCH_PIN;
-#endif
-#if NUM_MOTORS>5
- motors[5].step_pin =MOTOR_5_STEP_PIN;
- motors[5].dir_pin =MOTOR_5_DIR_PIN;
- motors[5].enable_pin =MOTOR_5_ENABLE_PIN;
- motors[5].limit_switch_pin=MOTOR_5_LIMIT_SWITCH_PIN;
-#endif
-
- int i;
- for(i=0;i0
- servos[0].attach(SERVO0_PIN);
-#endif
-#if NUM_SERVOS>1
- servos[1].attach(SERVO1_PIN);
-#endif
-#if NUM_SERVOS>2
- servos[2].attach(SERVO2_PIN);
-#endif
-#if NUM_SERVOS>3
- servos[3].attach(SERVO3_PIN);
-#endif
-#if NUM_SERVOS>4
- servos[4].attach(SERVO4_PIN);
-#endif
-
- current_segment=0;
- last_segment=0;
- Segment &old_seg = line_segments[get_prev_segment(last_segment)];
- old_seg.a[0].step_count=0;
-#if NUM_MOTORS>1
- old_seg.a[1].step_count=0;
-#endif
-#if NUM_MOTORS>2
- old_seg.a[2].step_count=0;
-#endif
-#if NUM_MOTORS>3
- old_seg.a[3].step_count=0;
-#endif
-#if NUM_MOTORS>4
- old_seg.a[4].step_count=0;
-#endif
-#if NUM_MOTORS>5
- old_seg.a[5].step_count=0;
-#endif
-
-#if NUM_SERVOS>0
- old_seg.a[NUM_MOTORS].step_count=0;
-#endif
-
- working_seg = NULL;
-
- // disable global interrupts
- noInterrupts();
- // set entire TCCR1A register to 0
- TCCR1A = 0;
- // set the overflow clock to 0
- TCNT1 = 0;
- // set compare match register to desired timer count
- OCR1A = 2000; // 1ms
- // turn on CTC mode
- TCCR1B = (1 << WGM12);
- // Set 8x prescaler
- TCCR1B = (TCCR1B & ~(0x07<=3
- if(arg0 < axies[2].limitMin) arg0=axies[2].limitMin;
- if(arg0 > axies[2].limitMax) arg0=axies[2].limitMax;
-
- axies[2].pos = arg0;
-
-#if NUM_SERVOS>0
- servos[0].write(arg0);
-#endif
-#endif
-}
-
-
-
-
-void recalculate_reverse2(Segment *prev,Segment *current,Segment *next) {
- if(current==NULL) return;
- if(next==NULL) return;
-
- if (current->feed_rate_start != current->feed_rate_start_max) {
- // If nominal length true, max junction speed is guaranteed to be reached. Only compute
- // for max allowable speed if block is decelerating and nominal length is false.
- if ((!current->nominal_length_flag) && (current->feed_rate_start_max > next->feed_rate_start)) {
- float v = min( current->feed_rate_start_max,
- max_speed_allowed(-acceleration,next->feed_rate_start,current->steps_total));
- current->feed_rate_start = v;
- } else {
- current->feed_rate_start = current->feed_rate_start_max;
- }
- current->recalculate_flag = true;
- }
-}
-
-
-void recalculate_reverse() {
-CRITICAL_SECTION_START
- int s = last_segment;
-CRITICAL_SECTION_END
-
- Segment *blocks[3] = {NULL,NULL,NULL};
- int count = SEGMOD( last_segment + current_segment + MAX_SEGMENTS );
- if(count>3) {
- while(s != current_segment) {
- s=get_prev_segment(s);
- blocks[2]=blocks[1];
- blocks[1]=blocks[0];
- blocks[0]=&line_segments[s];
- recalculate_reverse2(blocks[0],blocks[1],blocks[2]);
- }
- }
-}
-
-
-void recalculate_forward2(Segment *prev,Segment *current,Segment *next) {
- if(prev==NULL) return;
-
- // If the previous block is an acceleration block, but it is not long enough to complete the
- // full speed change within the block, we need to adjust the entry speed accordingly. Entry
- // speeds have already been reset, maximized, and reverse planned by reverse planner.
- // If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
- if (!prev->nominal_length_flag) {
- if (prev->feed_rate_start < current->feed_rate_start) {
- double feed_rate_start = min( current->feed_rate_start,
- max_speed_allowed(-acceleration,prev->feed_rate_start,prev->steps_total) );
-
- // Check for junction speed change
- if (current->feed_rate_start != feed_rate_start) {
- current->feed_rate_start = feed_rate_start;
- current->recalculate_flag = true;
- }
- }
- }
-}
-
-
-void recalculate_forward() {
- int s = current_segment;
- Segment *blocks[3] = {NULL,NULL,NULL};
-
- while(s != last_segment) {
- s=get_next_segment(s);
- blocks[0]=blocks[1];
- blocks[1]=blocks[2];
- blocks[2]=&line_segments[s];
- recalculate_forward2(blocks[0],blocks[1],blocks[2]);
- }
- recalculate_forward2(blocks[1],blocks[2],NULL);
-}
-
-
-int intersection_time(float accel,float distance,float start_speed,float end_speed) {
-#if 0
- return ( ( 2.0*accel*distance - start_speed*start_speed + end_speed*end_speed ) / (4.0*accel) );
-#else
- float t2 = ( start_speed - end_speed + accel * distance ) / ( 2.0 * accel );
- return distance - t2;
-#endif
-}
-
-
-void segment_update_trapezoid(Segment *s,float start_speed,float end_speed) {
- if(start_speedfeed_rate_max*s->feed_rate_max - start_speed*start_speed )/ (2.0*acceleration) );
- int steps_to_decel = floor( (end_speed*end_speed - s->feed_rate_max*s->feed_rate_max )/ -(2.0*acceleration) );
- //int steps_to_accel = ceil( ( s->feed_rate_max - start_speed ) / acceleration );
- //int steps_to_decel = floor( ( end_speed - s->feed_rate_max ) / -acceleration );
-
- int steps_at_top_speed = s->steps_total - steps_to_accel - steps_to_decel;
- if(steps_at_top_speed<0) {
- steps_to_accel = ceil( intersection_time(acceleration,s->steps_total,start_speed,end_speed) );
- steps_to_accel = max(steps_to_accel,0);
- steps_to_accel = min(steps_to_accel,s->steps_total);
- steps_at_top_speed=0;
- }
-/*
- Serial.print("M"); Serial.println(s->feed_rate_max);
- Serial.print("E"); Serial.println(end_speed);
- Serial.print("S"); Serial.println(start_speed);
- Serial.print("@"); Serial.println(acceleration);
- Serial.print("A"); Serial.println(steps_to_accel);
- Serial.print("D"); Serial.println(steps_to_decel);
-*/
-CRITICAL_SECTION_START
- if(!s->busy) {
- s->accel_until = steps_to_accel;
- s->decel_after = steps_to_accel+steps_at_top_speed;
- s->feed_rate_start = start_speed;
- s->feed_rate_end = end_speed;
- }
-CRITICAL_SECTION_END
-}
-
-
-void recalculate_trapezoids() {
- int s = current_segment;
- Segment *current;
- Segment *next = NULL;
-
- while(s != last_segment) {
- current = next;
- next = &line_segments[s];
- if (current) {
- // Recalculate if current block entry or exit junction speed has changed.
- if (current->recalculate_flag || next->recalculate_flag)
- {
- // NOTE: Entry and exit factors always > 0 by all previous logic operations.
- segment_update_trapezoid(current,current->feed_rate_start, next->feed_rate_start);
- current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
- }
- }
- s=get_next_segment(s);
- }
- // Last/newest block in buffer. Make sure the last block always ends motion.
- if(next != NULL) {
- segment_update_trapezoid(next, next->feed_rate_start, MIN_FEEDRATE);
- next->recalculate_flag = false;
- }
-}
-
-
-void recalculate_acceleration() {
- recalculate_reverse();
- recalculate_forward();
- recalculate_trapezoids();
-
-#if VERBOSE > 1
- //Serial.println("\nstart max,max,start,end,rate,total,up steps,cruise,down steps,nominal?");
- Serial.println("---------------");
- int s = current_segment;
-
- while(s != last_segment) {
- Segment *next = &line_segments[s];
- s=get_next_segment(s);
-// Serial.print(next->feed_rate_start_max);
-// Serial.print(F("\t")); Serial.print(next->feed_rate_max);
-// Serial.print(F("\t")); Serial.print(acceleration);
- Serial.print(F("\tS")); Serial.print(next->feed_rate_start);
-// Serial.print(F("\tE")); Serial.print(next->feed_rate_end);
- Serial.print(F("\t*")); Serial.print(next->steps_total);
- Serial.print(F("\tA")); Serial.print(next->accel_until);
- int after = (next->steps_total - next->decel_after);
- int total = next->steps_total - after - next->accel_until;
- Serial.print(F("\tT")); Serial.print(total);
- Serial.print(F("\tD")); Serial.print(after);
- Serial.print(F("\t")); Serial.println(next->nominal_length_flag==1?'*':' ');
- }
-#endif
-}
-
-
-void motor_set_step_count(long *a) {
- wait_for_empty_segment_buffer();
-
- Segment &old_seg = line_segments[get_prev_segment(last_segment)];
- old_seg.a[0].step_count=a[0];
-#if NUM_MOTORS>1
- old_seg.a[1].step_count=a[1];
-#endif
-#if NUM_MOTORS>2
- old_seg.a[2].step_count=a[2];
-#endif
-#if NUM_MOTORS>3
- old_seg.a[3].step_count=a[3];
-#endif
-#if NUM_MOTORS>4
- old_seg.a[4].step_count=a[4];
-#endif
-#if NUM_MOTORS>5
- old_seg.a[5].step_count=a[5];
-#endif
-#if NUM_SERVOS>0
- old_seg.a[NUM_MOTORS].step_count=a[NUM_MOTORS];
-#endif
-
- global_steps_0=0;
-#if NUM_MOTORS>1
- global_steps_1=0;
-#endif
-#if NUM_MOTORS>2
- global_steps_2=0;
-#endif
-#if NUM_MOTORS>3
- global_steps_3=0;
-#endif
-#if NUM_MOTORS>4
- global_steps_4=0;
-#endif
-#if NUM_MOTORS>5
- global_steps_5=0;
-#endif
-}
-
-
-/**
- * Step one motor one time in the currently set direction.
- * @input newx the destination x position
- * @input newy the destination y position
- **/
-void motor_onestep(int motor) {
-#ifdef VERBOSE
- Serial.print(motorNames[motor]);
-#endif
-
- digitalWrite(motors[motor].step_pin,HIGH);
- digitalWrite(motors[motor].step_pin,LOW);
-}
-
-
-/**
- * Set the clock 2 timer frequency.
- * @input desired_freq_hz the desired frequency
- * Different clock sources can be selected for each timer independently.
- * To calculate the timer frequency (for example 2Hz using timer1) you will need:
- */
-FORCE_INLINE unsigned short calc_timer(unsigned short desired_freq_hz) {
- if( desired_freq_hz > MAX_FEEDRATE ) desired_freq_hz = MAX_FEEDRATE;
- if( desired_freq_hz < MIN_FEEDRATE ) desired_freq_hz = MIN_FEEDRATE;
- old_feed_rate = desired_freq_hz;
-
- if( desired_freq_hz > 20000 ) {
- step_multiplier = 4;
- desired_freq_hz = (desired_freq_hz>>2)&0x3fff;
- } else if( desired_freq_hz > 10000 ) {
- step_multiplier = 2;
- desired_freq_hz = (desired_freq_hz>>1)&0x7fff;
- } else {
- step_multiplier = 1;
- }
-
- long counter_value = ( CLOCK_FREQ / 8 ) / desired_freq_hz;
- if( counter_value >= MAX_COUNTER ) {
- //Serial.print("this breaks the timer and crashes the arduino");
- //Serial.flush();
- counter_value = MAX_COUNTER - 1;
- } else if( counter_value < 100 ) {
- counter_value = 100;
- }
-
- return counter_value;
-}
-
-
-/**
- * Process all line segments in the ring buffer. Uses bresenham's line algorithm to move all motors.
- */
-ISR(TIMER1_COMPA_vect) {
- // segment buffer empty? do nothing
- if( working_seg == NULL ) {
- working_seg = segment_get_working();
-
- if( working_seg != NULL ) {
- // New segment!
- // set the direction pins
- digitalWrite( MOTOR_0_DIR_PIN, working_seg->a[0].dir );
- global_step_dir_0 = (working_seg->a[0].dir==HIGH)?1:-1;
-
- #if NUM_MOTORS>1
- digitalWrite( MOTOR_1_DIR_PIN, working_seg->a[1].dir );
- global_step_dir_1 = (working_seg->a[1].dir==HIGH)?1:-1;
- #endif
- #if NUM_MOTORS>2
- digitalWrite( MOTOR_2_DIR_PIN, working_seg->a[2].dir );
- global_step_dir_2 = (working_seg->a[2].dir==HIGH)?1:-1;
- #endif
- #if NUM_MOTORS>3
- digitalWrite( MOTOR_3_DIR_PIN, working_seg->a[3].dir );
- global_step_dir_3 = (working_seg->a[3].dir==HIGH)?1:-1;
- #endif
- #if NUM_MOTORS>4
- digitalWrite( MOTOR_4_DIR_PIN, working_seg->a[4].dir );
- global_step_dir_4 = (working_seg->a[4].dir==HIGH)?1:-1;
- #endif
- #if NUM_MOTORS>5
- digitalWrite( MOTOR_5_DIR_PIN, working_seg->a[5].dir );
- global_step_dir_5 = (working_seg->a[5].dir==HIGH)?1:-1;
- #endif
-
- #if NUM_SERVOS>0
- servos[0].write(working_seg->a[NUM_MOTORS].step_count);
- #endif
-
- // set frequency to segment feed rate
- nominal_OCR1A = calc_timer(working_seg->feed_rate_max);
- nominal_step_multiplier = step_multiplier;
-
- start_feed_rate = working_seg->feed_rate_start;
- end_feed_rate = working_seg->feed_rate_end;
- current_feed_rate = start_feed_rate;
- current_acceleration = acceleration;
- time_decelerating = 0;
- time_accelerating = calc_timer(start_feed_rate);
- OCR1A = time_accelerating;
-
- // defererencing some data so the loop runs faster.
- steps_total=working_seg->steps_total;
- steps_taken=0;
- delta0 = working_seg->a[0].absdelta; over0 = -(steps_total>>1);
- #if NUM_MOTORS>1
- delta1 = working_seg->a[1].absdelta; over1 = -(steps_total>>1);
- #endif
- #if NUM_MOTORS>2
- delta2 = working_seg->a[2].absdelta; over2 = -(steps_total>>1);
- #endif
- #if NUM_MOTORS>3
- delta3 = working_seg->a[3].absdelta; over3 = -(steps_total>>1);
- #endif
- #if NUM_MOTORS>4
- delta4 = working_seg->a[4].absdelta; over4 = -(steps_total>>1);
- #endif
- #if NUM_MOTORS>5
- delta5 = working_seg->a[5].absdelta; over5 = -(steps_total>>1);
- #endif
- accel_until=working_seg->accel_until;
- decel_after=working_seg->decel_after;
- return;
- } else {
- OCR1A = 2000; // wait 1ms
- return;
- }
- }
-
- if( working_seg != NULL ) {
- // move each axis
- for(uint8_t i=0;i 0) digitalWrite(MOTOR_0_STEP_PIN,LOW);
-#if NUM_MOTORS>1
- over1 += delta1;
- if(over1 > 0) digitalWrite(MOTOR_1_STEP_PIN,LOW);
-#endif
-#if NUM_MOTORS>2
- over2 += delta2;
- if(over2 > 0) digitalWrite(MOTOR_2_STEP_PIN,LOW);
-#endif
-#if NUM_MOTORS>3
- over3 += delta3;
- if(over3 > 0) digitalWrite(MOTOR_3_STEP_PIN,LOW);
-#endif
-#if NUM_MOTORS>4
- over4 += delta4;
- if(over4 > 0) digitalWrite(MOTOR_4_STEP_PIN,LOW);
-#endif
-#if NUM_MOTORS>5
- over5 += delta5;
- if(over5 > 0) digitalWrite(MOTOR_5_STEP_PIN,LOW);
-#endif
- // now that the pins have had a moment to settle, do the second half of the steps.
- // M0
- if(over0 > 0) {
- over0 -= steps_total;
- global_steps_0+=global_step_dir_0;
- digitalWrite(MOTOR_0_STEP_PIN,HIGH);
- }
-#if NUM_MOTORS>1
- // M1
- if(over1 > 0) {
- over1 -= steps_total;
- global_steps_1+=global_step_dir_1;
- digitalWrite(MOTOR_1_STEP_PIN,HIGH);
- }
-#endif
-#if NUM_MOTORS>2
- // M2
- if(over2 > 0) {
- over2 -= steps_total;
- global_steps_2+=global_step_dir_2;
- digitalWrite(MOTOR_2_STEP_PIN,HIGH);
- }
-#endif
-#if NUM_MOTORS>3
- // M3
- if(over3 > 0) {
- over3 -= steps_total;
- global_steps_3+=global_step_dir_3;
- digitalWrite(MOTOR_3_STEP_PIN,HIGH);
- }
-#endif
-#if NUM_MOTORS>4
- // M4
- if(over4 > 0) {
- over4 -= steps_total;
- global_steps_4+=global_step_dir_4;
- digitalWrite(MOTOR_4_STEP_PIN,HIGH);
- }
-#endif
-#if NUM_MOTORS>5
- // M5
- if(over5 > 0) {
- over5 -= steps_total;
- global_steps_5+=global_step_dir_5;
- digitalWrite(MOTOR_5_STEP_PIN,HIGH);
- }
-#endif
-
- // make a step
- steps_taken++;
- if(steps_taken>=steps_total) break;
- }
-
- // accel
- unsigned short t;
- if( steps_taken <= accel_until ) {
- current_feed_rate = start_feed_rate + (current_acceleration * time_accelerating / 1000000);
- if(current_feed_rate > working_seg->feed_rate_max) {
- current_feed_rate = working_seg->feed_rate_max;
- }
- t = calc_timer(current_feed_rate);
- OCR1A = t;
- time_accelerating+=t;
- } else if( steps_taken > decel_after ) {
- long end_feed_rate = current_feed_rate - (current_acceleration * time_decelerating / 1000000);
- if( end_feed_rate < working_seg->feed_rate_end ) {
- end_feed_rate = working_seg->feed_rate_end;
- }
- t = calc_timer(end_feed_rate);
- OCR1A = t;
- time_decelerating+=t;
- } else {
- OCR1A = nominal_OCR1A;
- step_multiplier = nominal_step_multiplier;
- }
-
- OCR1A = (OCR1A < (TCNT1 + 16)) ? (TCNT1 + 16) : OCR1A;
-
- // Is this segment done?
- if( steps_taken >= steps_total ) {
- // Move on to next segment without wasting an interrupt tick.
- working_seg = NULL;
- current_segment = get_next_segment(current_segment);
- }
- }
-}
-
-
-/**
- * @return 1 if buffer is full, 0 if it is not.
- */
-char segment_buffer_full() {
- int next_segment = get_next_segment(last_segment);
- return (next_segment == current_segment);
-}
-
-
-/**
- * Uses bresenham's line algorithm to move both motors
- * @param n (NUM_MOTORS+NUM_SERVOS) number of steps, one for each motor/servo
- **/
-void motor_line(long *n,float new_feed_rate) {
- // get the next available spot in the segment buffer
- int next_segment = get_next_segment(last_segment);
- while( next_segment == current_segment ) {
- // the buffer is full, we are way ahead of the motion system
- delay(1);
- }
-
- int prev_segment = get_prev_segment(last_segment);
- Segment &new_seg = line_segments[last_segment];
- Segment &old_seg = line_segments[prev_segment];
-
-/*
- int k;
- for(k=0;k1
- new_seg.a[1].step_count = n[1];
- new_seg.a[1].delta = n[1] - old_seg.a[1].step_count;
-#endif
-#if NUM_MOTORS>2
- new_seg.a[2].step_count = n[2];
- new_seg.a[2].delta = n[2] - old_seg.a[2].step_count;
-#endif
-#if NUM_MOTORS>3
- new_seg.a[3].step_count = n[3];
- new_seg.a[3].delta = n[3] - old_seg.a[3].step_count;
-#endif
-#if NUM_MOTORS>4
- new_seg.a[4].step_count = n[4];
- new_seg.a[4].delta = n[4] - old_seg.a[4].step_count;
-#endif
-#if NUM_MOTORS>5
- new_seg.a[5].step_count = n[5];
- new_seg.a[5].delta = n[5] - old_seg.a[5].step_count;
-#endif
-
-#if NUM_SERVOS>0
- new_seg.a[NUM_MOTORS].step_count = n[NUM_MOTORS];
- new_seg.a[NUM_MOTORS].delta = n[NUM_MOTORS] - old_seg.a[NUM_MOTORS].step_count;
-#endif
-
- new_seg.feed_rate_max = new_feed_rate;
- new_seg.busy=false;
-
- // the axis that has the most steps will control the overall acceleration
- new_seg.steps_total = 0;
- float len=0;
- int i;
- for(i=0;i1
- d = new_seg.a[1].delta_normalized - old_seg.a[1].delta_normalized; sum += d*d;
-#endif
-#if NUM_MOTORS>2
- d = new_seg.a[2].delta_normalized - old_seg.a[2].delta_normalized; sum += d*d;
-#endif
-#if NUM_MOTORS>3
- d = new_seg.a[3].delta_normalized - old_seg.a[3].delta_normalized; sum += d*d;
-#endif
-#if NUM_MOTORS>4
- d = new_seg.a[4].delta_normalized - old_seg.a[4].delta_normalized; sum += d*d;
-#endif
-#if NUM_MOTORS>5
- d = new_seg.a[5].delta_normalized - old_seg.a[5].delta_normalized; sum += d*d;
-#endif
-
-#if NUM_SERVOS>0
- d = new_seg.a[NUM_SERVOS].delta_normalized - old_seg.a[NUM_SERVOS].delta_normalized; sum += d*d;
-#endif
-
-
- float jerk = sqrt(sum);
- float vmax_junction_factor = 1.0;
- if(jerk> max_xy_jerk) {
- vmax_junction_factor = max_xy_jerk / jerk;
- }
- feed_rate_start_max = min( new_seg.feed_rate_max * vmax_junction_factor, old_seg.feed_rate_max );
- }
-
- float allowable_speed = max_speed_allowed(-acceleration, MIN_FEEDRATE, new_seg.steps_total);
-
-#if NUM_SERVOS>0
- // come to a stop for entering or exiting a Z move
- //if( new_seg.a[NUM_SERVOS].delta != 0 || old_seg.a[NUM_SERVOS].delta != 0 ) allowable_speed = MIN_FEEDRATE;
-#endif
-
- //Serial.print("max = "); Serial.println(feed_rate_start_max);
-// Serial.print("allowed = "); Serial.println(allowable_speed);
- new_seg.feed_rate_start_max = feed_rate_start_max;
- new_seg.feed_rate_start = min(feed_rate_start_max, allowable_speed);
-
- new_seg.nominal_length_flag = ( allowable_speed >= new_seg.feed_rate_max );
- new_seg.recalculate_flag = true;
-
- // when should we accelerate and decelerate in this segment?
- segment_update_trapezoid(&new_seg,new_seg.feed_rate_start,MIN_FEEDRATE);
-
- last_segment = next_segment;
-
- recalculate_acceleration();
-}
-
-
-void wait_for_empty_segment_buffer() {
- while( current_segment != last_segment );
-}
-
-
-/**
- * This file is part of makelangelo-firmware.
- *
- * makelangelo-firmware is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * makelangelo-firmware is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with makelangelo-firmware. If not, see .
- */
diff --git a/robot_arm3.ino b/robot_arm3.cpp
similarity index 95%
rename from robot_arm3.ino
rename to robot_arm3.cpp
index e6b3878..e9ffba2 100644
--- a/robot_arm3.ino
+++ b/robot_arm3.cpp
@@ -1,12 +1,13 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == ARM3
+#include "configure.h"
+#include "robot_arm3.h"
+#if MACHINE_STYLE == ARM3
/**
* Inverse Kinematics turns XY coordinates into step counts from each motor
@@ -14,7 +15,7 @@
* @param y cartesian coordinate
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *axies, long *motorStepArray) {
+void IK(const float *const axies, long *motorStepArray) {
float x = axies[0];
float y = axies[1];
float z = axies[2];
diff --git a/robot_arm3.h b/robot_arm3.h
index eae2f2c..16d4057 100644
--- a/robot_arm3.h
+++ b/robot_arm3.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == ARM3
diff --git a/robot_arm6.ino b/robot_arm6.cpp
similarity index 79%
rename from robot_arm6.ino
rename to robot_arm6.cpp
index 2bc09ff..d290200 100644
--- a/robot_arm6.ino
+++ b/robot_arm6.cpp
@@ -1,10 +1,12 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
+#include "configure.h"
+#include "robot_arm6.h"
+
#if MACHINE_STYLE == ARM6
#include "Vector3.h"
@@ -15,17 +17,41 @@
@param axies the cartesian coordinate
@param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *axies, long *motorStepArray) {
+void IK(const float *const axies, long *motorStepArray) {
+#if MACHINE_HARDWARE_VERSION==5
float x = -axies[0];
float y = -axies[1];
float z = -axies[2];
float u = -axies[3];
float v = axies[4];
float w = -axies[5];
+#endif
+
+#if MACHINE_HARDWARE_VERSION==6
+ // each of the xyz motors are differential to each other.
+ // to move only one motor means applying the negative of that value to the other two motors
+
+ // consider a two motor differential:
+ // if x moves, subtract x from y.
+ // if y moves, subtract y from x.
+ // so for three axis,
+ // for any axis N subtract the other two axies from this axis.
+
+ float a=axies[0]; // hand (G0 X*)
+ float b=axies[1]; // wrist (G0 Y*)
+ float c=axies[2]; // ulna (G0 Z*)
+
+ float x = a+b+c; // supposed to move hand
+ float y = b+c; // supposed to move wrist
+ float z = c; // supposed to move ulna
+ float u = -axies[3];
+ float v = axies[4];
+ float w = -axies[5];
+#endif
- motorStepArray[0] = x * MOTOR_0_STEPS_PER_TURN / 360.0;
- motorStepArray[1] = y * MOTOR_1_STEPS_PER_TURN / 360.0;
- motorStepArray[2] = z * MOTOR_2_STEPS_PER_TURN / 360.0;
+ motorStepArray[0] = y * MOTOR_0_STEPS_PER_TURN / 360.0; // WRIST
+ motorStepArray[1] = x * MOTOR_1_STEPS_PER_TURN / 360.0; // HAND
+ motorStepArray[2] = z * MOTOR_2_STEPS_PER_TURN / 360.0; // ULNA
motorStepArray[3] = u * MOTOR_3_STEPS_PER_TURN / 360.0;
motorStepArray[4] = v * MOTOR_4_STEPS_PER_TURN / 360.0;
motorStepArray[5] = w * MOTOR_5_STEPS_PER_TURN / 360.0;
@@ -65,7 +91,7 @@ void robot_findHome() {
int homeDirections[NUM_MOTORS] = {HOME_DIR_0,HOME_DIR_1,HOME_DIR_2,HOME_DIR_3,HOME_DIR_4,HOME_DIR_5};
- char i;
+ uint8_t i;
// for each stepper,
for (i = 0; i < NUM_MOTORS; ++i) {
Serial.print("Homing ");
diff --git a/robot_arm6.h b/robot_arm6.h
index 4734ada..045b1b3 100644
--- a/robot_arm6.h
+++ b/robot_arm6.h
@@ -3,21 +3,21 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == ARM6
#define MACHINE_STYLE_NAME "ARM6"
-#define MACHINE_HARDWARE_VERSION 5
+//#define MACHINE_HARDWARE_VERSION 5 // red sixi 2017-2018
+#define MACHINE_HARDWARE_VERSION 6 // yellow sixi 2019
#define STEP_DELAY (1000) // delay between steps, in milliseconds, when doing fixed tasks like homing
#define MAX_ACCELERATION (5000)
#define MIN_ACCELERATION (100)
-#define SUBDIVIDE_LINES
+//#define SUBDIVIDE_LINES
#define SEGMENT_PER_CM_LINE (2) // lines are split into segments. How long are the segments?
#define SEGMENT_PER_CM_ARC (3) // Arcs are split into segments. How long are the segments?
@@ -26,15 +26,97 @@
#define NUM_SERVOS (1)
#define NUM_TOOLS (1)
-#define MAX_FEEDRATE (4000.0) // depends on timer interrupt & hardware
-#define MIN_FEEDRATE (100)
+#define MAX_FEEDRATE (400.0) // depends on timer interrupt & hardware
+#define MIN_FEEDRATE (0)
#define MAX_JERK (5.0)
-#define DEFAULT_FEEDRATE (1500.0)
-#define DEFAULT_ACCELERATION (1500)
+#define DEFAULT_FEEDRATE (100.0)
+#define DEFAULT_ACCELERATION (500)
//#define HAS_LCD
#define HAS_SD
+#if MACHINE_HARDWARE_VERSION==6
+
+#define MOTOR_MICROSTEPS_EXT ((1.0*200.0)) // motor full steps * microstepping setting
+#define MOTOR_MICROSTEPS_MID ((1.0*400.0)) // motor full steps * microstepping setting
+
+#define NEMA17_CYCLOID_GEARBOX_RATIO (40.0)
+#define ELBOW_DOWNGEAR_RATIO (30.0/14.0)
+#define NEMA17_RATIO (NEMA17_CYCLOID_GEARBOX_RATIO*ELBOW_DOWNGEAR_RATIO)
+
+#define MOTOR_0_STEPS_PER_TURN (MOTOR_MICROSTEPS_MID*NEMA17_RATIO)
+#define MOTOR_1_STEPS_PER_TURN (MOTOR_MICROSTEPS_MID*NEMA17_RATIO)
+#define MOTOR_2_STEPS_PER_TURN (MOTOR_MICROSTEPS_EXT*NEMA17_RATIO)
+
+#define MOTOR_3_STEPS_PER_TURN (MOTOR_MICROSTEPS_MID*NEMA17_RATIO)
+#define MOTOR_4_STEPS_PER_TURN (MOTOR_MICROSTEPS_EXT*NEMA17_RATIO)
+#define MOTOR_5_STEPS_PER_TURN (MOTOR_MICROSTEPS_EXT*NEMA17_RATIO)
+
+
+// DIMENSIONS
+
+#define ADJUST_WRIST_ELBOW_ANGLE (14.036243)
+#define ADJUST_SHOULDER_ELBOW_ANGLE (11.309932)
+#define ADJUST_ULNA_ELBOW_ANGLE (26.56505117707799)
+
+// Relative offset from joint N to joint N+1.
+// shoulder pan
+#define OFFSET_0X 0
+#define OFFSET_0Y 0
+#define OFFSET_0Z 0
+// shoulder tilt
+#define OFFSET_1X 0
+#define OFFSET_1Y 0
+#define OFFSET_1Z 258
+// elbow tilt
+#define OFFSET_2X 0
+#define OFFSET_2Y 50
+#define OFFSET_2Z 250
+// elbow pan
+#define OFFSET_3X 0
+#define OFFSET_3Y -50
+#define OFFSET_3Z 100
+// wrist
+#define OFFSET_4X 0
+#define OFFSET_4Y 0
+#define OFFSET_4Z 100
+// wrist to wrist face
+#define OFFSET_5X 0
+#define OFFSET_5Y 0
+#define OFFSET_5Z 50
+
+// angle (degrees) when homing switches report in
+#define MIN_ANGLE_0 0
+#define MIN_ANGLE_1 -90
+#define MIN_ANGLE_2 -11.1
+#define MIN_ANGLE_3 0
+#define MIN_ANGLE_4 -90
+#define MIN_ANGLE_5 0
+
+#define MAX_ANGLE_0 180
+#define MAX_ANGLE_1 90
+#define MAX_ANGLE_2 (180-11.1)
+#define MAX_ANGLE_3 180
+#define MAX_ANGLE_4 90
+#define MAX_ANGLE_5 180
+
+#define HOME_ANGLE_0 MIN_ANGLE_0
+#define HOME_ANGLE_1 MIN_ANGLE_1
+#define HOME_ANGLE_2 MIN_ANGLE_2
+#define HOME_ANGLE_3 MIN_ANGLE_3
+#define HOME_ANGLE_4 MIN_ANGLE_4
+#define HOME_ANGLE_5 MIN_ANGLE_5
+
+#define HOME_DIR_0 HIGH
+#define HOME_DIR_1 HIGH
+#define HOME_DIR_2 LOW
+#define HOME_DIR_3 HIGH
+#define HOME_DIR_4 LOW
+#define HOME_DIR_5 HIGH
+
+#endif // MACHINE_HARDWARE_VERSION==6
+#if MACHINE_HARDWARE_VERSION==5
+
#define MOTOR_MICROSTEPS_EXT (1600) // motor full steps * microstepping setting
#define MOTOR_MICROSTEPS_MID (3200) // motor full steps * microstepping setting
#define MOTOR_MICROSTEPS_INT ( 200) // motor full steps * microstepping setting
@@ -49,6 +131,7 @@
#define MOTOR_4_STEPS_PER_TURN ((unsigned long)MOTOR_MICROSTEPS_INT*NEMA14_RATIO)
#define MOTOR_5_STEPS_PER_TURN ((unsigned long)MOTOR_MICROSTEPS_INT*NEMA08_RATIO)
+
// DIMENSIONS
#define ADJUST_WRIST_ELBOW_ANGLE (14.036243)
@@ -110,8 +193,9 @@
#define HOME_DIR_4 LOW
#define HOME_DIR_5 HIGH
+#endif // MACHINE_HARDWARE_VERSION==5
+
#endif // #ifdef ARM6
#endif // #ifndef ROBOT_ARM6_H
-
diff --git a/robot_corexy.ino b/robot_corexy.cpp
similarity index 86%
rename from robot_corexy.ino
rename to robot_corexy.cpp
index a132172..52cf593 100644
--- a/robot_corexy.ino
+++ b/robot_corexy.cpp
@@ -1,19 +1,20 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == COREXY
+#include "configure.h"
+#include "robot_corexy.h"
+#if MACHINE_STYLE == COREXY
/**
* Inverse Kinematics turns XY coordinates into lengths L1,L2
* @param axies the cartesian coordinate
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *axies, long *motorStepArray) {
+void IK(const float *const axies, long *motorStepArray) {
float x = axies[0];
float y = axies[1];
float z = axies[2];
diff --git a/robot_corexy.h b/robot_corexy.h
index 750c6bb..07cb484 100644
--- a/robot_corexy.h
+++ b/robot_corexy.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == COREXY
diff --git a/robot_delta.ino b/robot_delta.cpp
similarity index 96%
rename from robot_delta.ino
rename to robot_delta.cpp
index bad1e75..64ef835 100644
--- a/robot_delta.ino
+++ b/robot_delta.cpp
@@ -1,12 +1,13 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == DELTA
+#include "configure.h"
+#include "robot_delta.h"
+#if MACHINE_STYLE == DELTA
#define SQRT3 (sqrt(3.0))
#define SIN120 (SQRT3/2.0)
@@ -21,7 +22,7 @@
* @param axies the cartesian coordinate
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *axies, long *motorStepArray) {
+void IK(const float *const axies, long *motorStepArray) {
float x = axies[0];
float y = axies[1];
float z = axies[2];
diff --git a/robot_delta.h b/robot_delta.h
index 6ef5e30..2e909e3 100644
--- a/robot_delta.h
+++ b/robot_delta.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == DELTA
diff --git a/robot_polargraph.ino b/robot_polargraph.cpp
similarity index 97%
rename from robot_polargraph.ino
rename to robot_polargraph.cpp
index 95f1264..16f004c 100644
--- a/robot_polargraph.ino
+++ b/robot_polargraph.cpp
@@ -1,19 +1,21 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == POLARGRAPH
+#include "configure.h"
+#include "robot_polargraph.h"
+#include "eeprom.h"
+#if MACHINE_STYLE == POLARGRAPH
/**
* Inverse Kinematics turns XY coordinates into step counts from each motor
* @param axies the cartesian coordinate
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *cartesian, long *motorStepArray) {
+void IK(const float *const cartesian, long *motorStepArray) {
float dy,dx;
// find length to M1
float limit_xmin = axies[0].limitMin;
@@ -76,6 +78,7 @@ int FK(long *motorStepArray,float *cartesian) {
Serial.print("C1="); Serial.println(cartesian[1]);
Serial.print("C2="); Serial.println(cartesian[2]);
*/
+ return 0;
}
@@ -255,7 +258,7 @@ void robot_findHome() {
offset[2]=axies[2].pos;
Serial.print(F("Homing to ")); Serial.print (axies[0].homePos);
Serial.print(','); Serial.println(axies[1].homePos);
- lineSafe(offset, feed_rate);
+ lineSafe(offset, DEFAULT_FEEDRATE);
Serial.println(F("Done."));
#endif // USER_LIMIT_SWITCH
diff --git a/robot_polargraph.h b/robot_polargraph.h
index b826f6f..82a1004 100644
--- a/robot_polargraph.h
+++ b/robot_polargraph.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == POLARGRAPH
@@ -15,7 +14,7 @@
#define MACHINE_HAS_LIFTABLE_PEN
#define SUBDIVIDE_LINES
-#define SEGMENT_PER_CM_LINE (2) // lines are subdivided. How long are the divisions?
+#define SEGMENT_PER_CM_LINE (0.5) // lines are subdivided. How long are the divisions?
#define SEGMENT_PER_CM_ARC (3) // Arcs are subdivided. How long are the divisions?
// servo angles for pen control
@@ -27,28 +26,31 @@
#define NUM_SERVOS (1)
#define NUM_TOOLS (1)
-#define MAX_FEEDRATE (20000.0) // depends on timer interrupt & hardware
-#define MIN_FEEDRATE (100)
-#define DEFAULT_FEEDRATE (9000.0)
+#define MAX_FEEDRATE (100.0) // depends on timer interrupt & hardware
+#define MIN_FEEDRATE (0.0)
+#define DEFAULT_FEEDRATE (90.0)
-#define MAX_ACCELERATION (5000)
-#define MIN_ACCELERATION (100)
-#define DEFAULT_ACCELERATION (2500)
+#define MAX_ACCELERATION (500.0)
+#define MIN_ACCELERATION (0.0)
+#define DEFAULT_ACCELERATION (180.0)
-#define MAX_JERK (5.0)
+#define MAX_JERK (10.0)
#if MACHINE_HARDWARE_VERSION == 5
-#define USE_LIMIT_SWITCH (1) // Comment out this line to disable findHome and limit switches
-#define HAS_SD // comment this out if there is no SD card
-#define HAS_LCD // comment this out if there is no SMART LCD controller
+#define USE_LIMIT_SWITCH
+#define HAS_SD
+#define HAS_LCD
#endif
#if MACHINE_HARDWARE_VERSION == 3
-#define HAS_SD // comment this out if there is no SD card
-#define HAS_LCD // comment this out if there is no SMART LCD controller
+#define HAS_SD
+#define HAS_LCD
#endif
+extern void calibrateBelts();
+extern void recordHome();
+
#endif // #ifdef POLARGRAPH
diff --git a/robot_skycam.ino b/robot_skycam.cpp
similarity index 90%
rename from robot_skycam.ino
rename to robot_skycam.cpp
index 9f19816..d1409a0 100644
--- a/robot_skycam.ino
+++ b/robot_skycam.cpp
@@ -1,20 +1,20 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == SKYCAM
-
+#include "configure.h"
+#include "robot_skycam.h"
+#if MACHINE_STYLE == SKYCAM
/**
* Inverse Kinematics turns XY coordinates into lengths of belt from each motor
* @param axies the cartesian coordinates
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *cartesian, long *motorStepArray) {
+void IK(const float *const cartesian, long *motorStepArray) {
float x = cartesian[0];
float y = cartesian[1];
float z = cartesian[2];
diff --git a/robot_skycam.h b/robot_skycam.h
index cf50374..1ba52e7 100644
--- a/robot_skycam.h
+++ b/robot_skycam.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == SKYCAM
diff --git a/robot_stewart.cpp b/robot_stewart.cpp
new file mode 100644
index 0000000..a7a95ca
--- /dev/null
+++ b/robot_stewart.cpp
@@ -0,0 +1,427 @@
+//------------------------------------------------------------------------------
+// Makelangelo - firmware for various robot kinematic models
+// dan@marginallycelver.com 2013-12-26
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+//------------------------------------------------------------------------------
+
+#include "configure.h"
+#include "robot_stewart.h"
+
+#if MACHINE_STYLE == STEWART
+
+#include "Vector3.h"
+
+#define NUM_ARMS (6)
+
+struct EndEffector {
+ Vector3 up;
+ Vector3 left;
+ Vector3 forward;
+ Vector3 pos;
+ Vector3 relative;
+ float r, p, y; // roll, pitch, yaw
+};
+
+struct StewartArm {
+ Vector3 shoulder;
+ Vector3 elbow;
+ Vector3 shoulder_to_elbow;
+ Vector3 wrist;
+
+ float angle;
+};
+
+struct StewartPlatform {
+ StewartArm arms[NUM_ARMS];
+ EndEffector ee;
+};
+
+
+StewartPlatform robot;
+
+
+void stewartDemo() {
+ float pos[NUM_AXIES] = {0,0,0,0,0,0};
+ int i,j;
+
+ // linear moves
+ for(j=0;j<3;++j) {
+ for(i=0;i<5;++i) {
+ pos[j]=2;
+ lineSafe(pos,feed_rate);
+ pos[j]=-2;
+ lineSafe(pos,feed_rate);
+ }
+ pos[j]=0;
+ lineSafe(pos,feed_rate);
+ }
+
+ // tilting
+ for(j=4;j<6;++j) {
+ for(i=0;i<5;++i) {
+ pos[j]=10;
+ lineSafe(pos,feed_rate);
+ pos[j]=-10;
+ lineSafe(pos,feed_rate);
+ }
+ pos[j]=0;
+ lineSafe(pos,feed_rate);
+ }
+
+ // combos
+ for(j=0;j<3;++j) {
+ for(i=0;i<360*5;i+=10) {
+ pos[ j ]=2*sin(((float)i/180.0)*PI);
+ pos[(j+1)%3]=2*cos(((float)i/180.0)*PI);
+ lineSafe(pos,feed_rate);
+ }
+ pos[ j ]=0;
+ pos[(j+1)%3]=0;
+ lineSafe(pos,feed_rate);
+ }
+
+ // combos rotation
+ for(j=4;j<6;++j) {
+ for(i=0;i<360*5;i+=10) {
+ pos[ j ]=10.0*sin(((float)i/180.0)*PI);
+ pos[3+((j-3+1)%3)]=10.0*cos(((float)i/180.0)*PI);
+ lineSafe(pos,feed_rate);
+ }
+ pos[ j ]=0;
+ pos[3+((j-3+1)%3)]=0;
+ lineSafe(pos,feed_rate);
+ }
+
+ // combos random
+ for(j=0;j<50;++j) {
+ pos[0]=2*cos(((float)random(360)/180.0)*PI);
+ pos[1]=2*cos(((float)random(360)/180.0)*PI);
+ pos[2]=1.5*cos(((float)random(360)/180.0)*PI);
+ pos[3]=10.0*cos(((float)random(360)/180.0)*PI);
+ pos[4]=10.0*cos(((float)random(360)/180.0)*PI);
+ pos[5]=10.0*cos(((float)random(360)/180.0)*PI);
+ lineSafe(pos,feed_rate);
+ }
+ for(i=0;i 0
+ for (i = 0; i < NUM_ARMS; ++i) {
+ StewartArm &arm = robot.arms[i];
+ Serial.print(i);
+ Serial.print("\twrist =");
+ Serial.print(arm.wrist.x);
+ Serial.print(F(","));
+ Serial.print(arm.wrist.y);
+ Serial.print(F(","));
+ Serial.println(arm.wrist.z);
+ }
+#endif
+}
+
+
+/**
+ update the elbow positions according to the wrists and shoulders, then find shoulder angle.
+*/
+void stewart_update_shoulder_angles() {
+ Vector3 ortho, w, wop, temp, r;
+ float a, b, d, r1, r0, hh, y, x;
+
+ int i;
+ for (i = 0; i < NUM_ARMS; ++i) {
+ StewartArm &arm = robot.arms[i];
+
+#if VERBOSE > 0
+ Serial.print(i);
+#endif
+
+ // project wrist position onto plane of bicep (wop)
+ ortho.x = cos((i / 2) * PI * 2.0f / 3.0f);
+ ortho.y = sin((i / 2) * PI * 2.0f / 3.0f);
+ ortho.z = 0;
+
+ w = arm.wrist - arm.shoulder;
+
+ a = w | ortho; //endeffector' distance
+ wop = w - (ortho * a);
+ //arm.wop.pos=wop + arm.shoulder; // e' location
+ //vector_add(arm.wop,wop,arm.shoulder);
+
+ // because wop is projected onto the bicep plane, wop-elbow is not the same as wrist-elbow.
+ // we need to find wop-elbow to calculate the angle at the shoulder.
+ b = sqrt(FOREARM_LENGTH * FOREARM_LENGTH - a * a); // e'j distance
+
+ // use intersection of circles to find elbow point.
+ //a = (r0r0 - r1r1 + d*d ) / (2 d)
+ r1 = b; // circle 1 centers on e'
+ r0 = BICEP_LENGTH; // circle 0 centers on shoulder
+ d = wop.Length();
+ // distance from shoulder to the midpoint between the two possible intersections
+ a = ( r0 * r0 - r1 * r1 + d * d ) / ( 2 * d );
+
+#if VERBOSE > 0
+ Serial.print("\tb =");
+ Serial.println(b);
+ Serial.print("\td =");
+ Serial.println(d);
+ Serial.print("\ta =");
+ Serial.println(a);
+#endif
+
+ // normalize wop
+ wop /= d;
+ // find the midpoint
+ temp = arm.shoulder + (wop * a);
+ // with a and r0 we can find h, the distance from midpoint to intersections.
+ hh = sqrt(r0 * r0 - a * a);
+ // get a normal to the line wop in the plane orthogonal to ortho
+ r = ortho ^ wop;
+ if (i % 2 == 0) arm.elbow = temp + r * hh;
+ else arm.elbow = temp - r * hh;
+
+ // use atan2 to find theta
+ temp = arm.elbow - arm.shoulder;
+ y = -temp.z;
+ temp.z = 0;
+ x = temp.Length();
+ if ( ( arm.shoulder_to_elbow | temp ) < 0 ) x = -x;
+ arm.angle = degrees(atan2(-y, x));
+#if VERBOSE > 0
+ Serial.print(i);
+ Serial.print("\tangle =");
+ Serial.println(arm.angle);
+#endif
+ }
+}
+
+
+/**
+ Inverse Kinematics turns XY coordinates into step counts from each motor
+ @param axies the cartesian coordinate
+ @param motorStepArray a measure of each belt to that plotter position
+*/
+void IK(const float *const cartesian, long *motorStepArray) {
+ float x = cartesian[0];
+ float y = cartesian[1];
+ float z = cartesian[2];
+ float u = cartesian[3];
+ float v = cartesian[4];
+ float w = cartesian[5];
+
+ Vector3 mov(x, y, z);
+ Vector3 rpy(u, v, w);
+
+ stewart_update_endeffector(mov, rpy);
+ stewart_update_wrists();
+ stewart_update_shoulder_angles();
+
+ int i;
+ for (i = 0; i < NUM_ARMS; ++i) {
+ motorStepArray[i] = robot.arms[i].angle * MICROSTEP_PER_DEGREE;
+ }
+}
+
+
+/**
+ Forward Kinematics - turns step counts into XY coordinates
+ @param motorStepArray a measure of each belt to that plotter position
+ @param axies the resulting cartesian coordinate
+ @return 0 if no problem, 1 on failure.
+*/
+int FK(long *motorStepArray, float *axies) {
+ return 0;
+}
+
+
+/**
+ Build a virtual model of the stewart shoulders for calculating angles later.
+*/
+void stewart_build_shoulders() {
+ Vector3 n, o, n1, o1;
+ float c, s;
+ int i;
+ for (i = 0; i < 3; ++i) {
+ StewartArm &arma = robot.arms[i * 2 + 0];
+ StewartArm &armb = robot.arms[i * 2 + 1];
+
+ c = cos(i * PI * 2.0f / 3.0f);
+ s = sin(i * PI * 2.0f / 3.0f);
+
+ n = robot.ee.forward;
+ o = robot.ee.up ^ robot.ee.forward;
+ o.Normalize();
+
+ n1 = n * c + o * s;
+ o1 = n * -s + o * c;
+
+ arma.shoulder = n1 * B2S_X - o1 * B2S_Y + robot.ee.up * B2S_Z;
+ armb.shoulder = n1 * B2S_X + o1 * B2S_Y + robot.ee.up * B2S_Z;
+ arma.elbow = n1 * B2S_X - o1 * (B2S_Y + BICEP_LENGTH) + robot.ee.up * B2S_Z;
+ armb.elbow = n1 * B2S_X + o1 * (B2S_Y + BICEP_LENGTH) + robot.ee.up * B2S_Z;
+ arma.shoulder_to_elbow = -o1;
+ armb.shoulder_to_elbow = o1;
+ }
+
+#if VERBOSE > 0
+ for (i = 0; i < 6; ++i) {
+ StewartArm &arm = robot.arms[i];
+ Serial.print(i);
+ Serial.print("\ts =");
+ Serial.print(arm.shoulder.x);
+ Serial.print(F(","));
+ Serial.print(arm.shoulder.y);
+ Serial.print(F(","));
+ Serial.print(arm.shoulder.z);
+
+ Serial.print("\te =");
+ Serial.print(arm.elbow.x);
+ Serial.print(F(","));
+ Serial.print(arm.elbow.y);
+ Serial.print(F(","));
+ Serial.println(arm.elbow.z);
+ }
+#endif
+}
+
+
+void robot_setup() {
+}
+
+
+void robot_findHome() {
+ wait_for_empty_segment_buffer();
+ motor_engage();
+
+ findStepDelay();
+
+ Serial.println(F("Finding..."));
+
+ uint8_t i, hits;
+ // back up until all switches are hitG
+ do {
+ hits = 0;
+ // for each stepper,
+ for (i = 0; i < NUM_MOTORS; ++i) {
+ digitalWrite(motors[i].dir_pin, HIGH);
+ // if this switch hasn't been hit yet
+ if (digitalRead(motors[i].limit_switch_pin) == HIGH) {
+ // move "down"
+ //Serial.print('|');
+ digitalWrite(motors[i].step_pin, HIGH);
+ digitalWrite(motors[i].step_pin, LOW);
+ } else {
+ ++hits;
+ //Serial.print('*');
+ }
+ }
+ //Serial.println();
+ pause(step_delay);
+ } while (hits < NUM_MOTORS);
+
+ // The arms are 19.69 degrees from straight down when they hit the switcrobot.
+ // @TODO: This could be better customized in firmware.
+ uint32_t steps_to_zero = SWITCH_ANGLE * MICROSTEP_PER_DEGREE;
+
+ Serial.println(F("Homing..."));
+#if VERBOSE > 0
+ Serial.print("steps=");
+ Serial.println(steps_to_zero);
+#endif
+ for (uint32_t j = 0; j < steps_to_zero; ++j) {
+ for (i = 0; i < NUM_MOTORS; ++i) {
+ digitalWrite(motors[i].dir_pin, LOW);
+ digitalWrite(motors[i].step_pin, HIGH);
+ digitalWrite(motors[i].step_pin, LOW);
+ }
+ //Serial.println(steps_to_zero-j,DEC);
+ pause(step_delay);
+ }
+
+ // set robot to home position
+
+ Vector3 zero(0, 0, 0);
+ stewart_update_endeffector(zero, zero);
+ stewart_build_shoulders();
+ stewart_update_wrists();
+
+ // find the starting height of the end effector at home position
+ // @TODO: project wrist-on-bicep to get more accurate distance
+ Vector3 el = robot.arms[0].elbow;
+ Vector3 wr = robot.arms[0].wrist;
+ float aa = (el.y - wr.y);
+ float cc = FOREARM_LENGTH;
+ float bb = sqrt((cc * cc) - (aa * aa));
+ aa = el.x - wr.x;
+ cc = bb;
+ bb = sqrt((cc * cc) - (aa * aa));
+ robot.ee.relative.set(0, 0, bb + B2S_Z - T2W_Z);
+
+ float zeros[6] = {0, 0, 0, 0, 0, 0};
+ teleport(zeros);
+}
+
+
+
+#endif
diff --git a/robot_stewart.h b/robot_stewart.h
index 3d09fe4..3a97b54 100644
--- a/robot_stewart.h
+++ b/robot_stewart.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == STEWART
@@ -12,11 +11,6 @@
#define MACHINE_STYLE_NAME "STEWART"
#define MACHINE_HARDWARE_VERSION 5
-#define STEP_DELAY (50) // delay between steps, in milliseconds, when doing fixed tasks like homing
-
-#define MAX_ACCELERATION (5000)
-#define MIN_ACCELERATION (100)
-
#define SUBDIVIDE_LINES
#define SEGMENT_PER_CM_LINE (2) // lines are split into segments. How long are the segments?
#define SEGMENT_PER_CM_ARC (3) // Arcs are split into segments. How long are the segments?
@@ -30,16 +24,21 @@
#define NUM_MOTORS (6)
#define NUM_SERVOS (0)
-#define MAX_FEEDRATE (9000.0) // depends on timer interrupt & hardware
-#define MIN_FEEDRATE (100)
+#define MAX_FEEDRATE (2000.0) // depends on timer interrupt & hardware
+#define MIN_FEEDRATE (0)
+#define DEFAULT_FEEDRATE (60.0)
+
+#define MAX_ACCELERATION (1000)
+#define MIN_ACCELERATION (0)
+#define DEFAULT_ACCELERATION (500)
+
#define MAX_JERK (5.0)
-#define DEFAULT_FEEDRATE (7000.0)
-#define DEFAULT_ACCELERATION (2500)
+#define MAX_SEGMENTS (16)
#define BICEP_LENGTH ( 5.000)
#define FOREARM_LENGTH (16.750)
-#define SWITCH_ANGLE (18.690)
+#define SWITCH_ANGLE (90-18.690)
// top center to wrist hole (relative): X7.635 Y+/-0.553 Z0.87
#define T2W_X ( 7.635)
#define T2W_Y ( 0.553)
@@ -50,8 +49,9 @@
#define B2S_Z ( 6.618)
+extern void stewartDemo();
+
#endif // #ifdef STEWART
#endif // #ifndef ROBOT_STEWART_H
-
diff --git a/robot_stewart.ino b/robot_stewart.ino
deleted file mode 100644
index 63aa2f5..0000000
--- a/robot_stewart.ino
+++ /dev/null
@@ -1,346 +0,0 @@
-//------------------------------------------------------------------------------
-// Makelangelo - firmware for various robot kinematic models
-// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
-//------------------------------------------------------------------------------
-
-#if MACHINE_STYLE == STEWART
-
-
-#define NUM_ARMS (6)
-
-struct EndEffector {
- Vector3 up;
- Vector3 left;
- Vector3 forward;
- Vector3 pos;
- Vector3 relative;
- float r,p,y; // roll, pitch, yaw
-};
-
-struct StewartArm {
- Vector3 shoulder;
- Vector3 elbow;
- Vector3 shoulder_to_elbow;
- Vector3 wrist;
-
- float angle;
-};
-
-struct StewartPlatform {
- StewartArm arms[NUM_ARMS];
- EndEffector ee;
-};
-
-
-StewartPlatform robot;
-
-
-/**
- * Inverse Kinematics turns XY coordinates into step counts from each motor
- * @param axies the cartesian coordinate
- * @param motorStepArray a measure of each belt to that plotter position
- */
-void IK(float *cartesian, long *motorStepArray) {
- float x = cartesian[0];
- float y = cartesian[1];
- float z = cartesian[2];
- float u = cartesian[3];
- float v = cartesian[4];
- float w = cartesian[5];
-
- Vector3 mov(x,y,z);
- Vector3 rpy(u,v,w);
-
- stewart_update_endeffector(mov,rpy);
- stewart_update_wrists();
- stewart_update_shoulder_angles();
-
- int i;
- for(i=0;i 0
- for(i=0;i 0
- Serial.print(i);
-#endif
-
- // project wrist position onto plane of bicep (wop)
- ortho.x=cos((i/2)*PI*2.0f/3.0f);
- ortho.y=sin((i/2)*PI*2.0f/3.0f);
- ortho.z=0;
-
- w = arm.wrist - arm.shoulder;
-
- a=w | ortho; //endeffector' distance
- wop = w - (ortho * a);
- //arm.wop.pos=wop + arm.shoulder; // e' location
- //vector_add(arm.wop,wop,arm.shoulder);
-
- // because wop is projected onto the bicep plane, wop-elbow is not the same as wrist-elbow.
- // we need to find wop-elbow to calculate the angle at the shoulder.
- b=sqrt(FOREARM_LENGTH*FOREARM_LENGTH-a*a); // e'j distance
-
- // use intersection of circles to find elbow point.
- //a = (r0r0 - r1r1 + d*d ) / (2 d)
- r1=b; // circle 1 centers on e'
- r0=BICEP_LENGTH; // circle 0 centers on shoulder
- d=wop.Length();
- // distance from shoulder to the midpoint between the two possible intersections
- a = ( r0 * r0 - r1 * r1 + d*d ) / ( 2*d );
-
-#if VERBOSE > 0
- Serial.print("\tb =");
- Serial.println(b);
- Serial.print("\td =");
- Serial.println(d);
- Serial.print("\ta =");
- Serial.println(a);
-#endif
-
- // normalize wop
- wop /= d;
- // find the midpoint
- temp=arm.shoulder+(wop*a);
- // with a and r0 we can find h, the distance from midpoint to intersections.
- hh=sqrt(r0*r0-a*a);
- // get a normal to the line wop in the plane orthogonal to ortho
- r = ortho ^ wop;
- if(i%2==0) arm.elbow=temp + r * hh;
- else arm.elbow=temp - r * hh;
-
- // use atan2 to find theta
- temp=arm.elbow-arm.shoulder;
- y=-temp.z;
- temp.z=0;
- x=temp.Length();
- if( ( arm.shoulder_to_elbow | temp ) < 0 ) x=-x;
- arm.angle = degrees(atan2(-y,x));
-#if VERBOSE > 0
- Serial.print(i);
- Serial.print("\tangle =");
- Serial.println(arm.angle);
-#endif
- }
-}
-
-
-/**
- * Forward Kinematics - turns step counts into XY coordinates
- * @param motorStepArray a measure of each belt to that plotter position
- * @param axies the resulting cartesian coordinate
- * @return 0 if no problem, 1 on failure.
- */
-int FK(long *motorStepArray,float *axies) {
- return 0;
-}
-
-
-void robot_findHome() {
- motor_engage();
-
- char i,hits;
- // back up until all switches are hit
- do {
- hits=0;
- // for each stepper,
- for(i=0;i0);
-
- // The arms are 19.69 degrees from straight down when they hit the switcrobot.
- // @TODO: This could be better customized in firmware.
- long steps_to_zero = SWITCH_ANGLE * MICROSTEP_PER_DEGREE;
-
- Serial.println(F("Homing..."));
-#if VERBOSE > 0
- Serial.print("steps=");
- Serial.println(steps_to_zero);
-#endif
- char keepGoing;
- for(int j=0;i 0
- for(i=0;i<6;++i) {
- StewartArm &arm=robot.arms[i];
- Serial.print(i);
- Serial.print("\ts =");
- Serial.print(arm.shoulder.x);
- Serial.print(F(","));
- Serial.print(arm.shoulder.y);
- Serial.print(F(","));
- Serial.print(arm.shoulder.z);
-
- Serial.print("\te =");
- Serial.print(arm.elbow.x);
- Serial.print(F(","));
- Serial.print(arm.elbow.y);
- Serial.print(F(","));
- Serial.println(arm.elbow.z);
- }
-#endif
-}
-
-
-void robot_setup() {
-}
-
-
-
-#endif
diff --git a/robot_traditionalxy.ino b/robot_traditionalxy.cpp
similarity index 77%
rename from robot_traditionalxy.ino
rename to robot_traditionalxy.cpp
index 79f1a8e..2839067 100644
--- a/robot_traditionalxy.ino
+++ b/robot_traditionalxy.cpp
@@ -1,26 +1,28 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == TRADITIONALXY
+#include "configure.h"
+#include "robot_traditionalxy.h"
+#if MACHINE_STYLE == TRADITIONALXY
+#include
/**
* Inverse Kinematics turns XY coordinates into step counts from each motor
* @param x cartesian coordinate
* @param y cartesian coordinate
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *cartesian, long *motorStepArray) {
+void IK(const float *const cartesian, long *motorStepArray) {
float x = cartesian[0];
float y = cartesian[1];
float z = cartesian[2];
- motorStepArray[0] = lround((x) / THREAD_PER_STEP);
- motorStepArray[1] = lround((y) / THREAD_PER_STEP);
+ motorStepArray[0] = lround(x / THREAD_PER_STEP);
+ motorStepArray[1] = lround(y / THREAD_PER_STEP);
motorStepArray[NUM_MOTORS] = z;
}
diff --git a/robot_traditionalxy.h b/robot_traditionalxy.h
index b124367..89158a1 100644
--- a/robot_traditionalxy.h
+++ b/robot_traditionalxy.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
#if MACHINE_STYLE == TRADITIONALXY
@@ -15,9 +14,6 @@
#define STEP_DELAY (50) // delay between steps, in milliseconds, when doing fixed tasks like homing
-#define MAX_ACCELERATION (5000)
-#define MIN_ACCELERATION (100)
-
// servo angles for pen control
#define PEN_UP_ANGLE (90)
#define PEN_DOWN_ANGLE (50) // Some steppers don't like 0 degrees
@@ -27,15 +23,21 @@
#define NUM_SERVOS (1)
#define NUM_TOOLS (1)
-#define MAX_FEEDRATE (9000.0) // depends on timer interrupt & hardware
-#define MIN_FEEDRATE (100)
+#define MAX_FEEDRATE (1500.0) // depends on timer interrupt & hardware
+#define MIN_FEEDRATE (0.0)
+#define DEFAULT_FEEDRATE (200.0)
+
+#define MAX_ACCELERATION (2000.0)
+#define MIN_ACCELERATION (0.0)
+#define DEFAULT_ACCELERATION (1000.0)
#define MAX_JERK (5.0)
-#define DEFAULT_FEEDRATE (7000.0)
-#define DEFAULT_ACCELERATION (2500)
+
+#define SUBDIVIDE_LINES
+#define SEGMENT_PER_CM_LINE (1) // lines are subdivided. How long are the divisions?
+#define SEGMENT_PER_CM_ARC (3) // Arcs are subdivided. How long are the divisions?
#endif // #ifdef TRADITIONALXY
#endif // #ifndef ROBOT_TRADITIONALXY_H
-
diff --git a/robot_zarplotter.ino b/robot_zarplotter.cpp
similarity index 93%
rename from robot_zarplotter.ino
rename to robot_zarplotter.cpp
index fe17c74..a60ace7 100644
--- a/robot_zarplotter.ino
+++ b/robot_zarplotter.cpp
@@ -1,20 +1,20 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
-#if MACHINE_STYLE == ZARPLOTTER
-
+#include "configure.h"
+#include "robot_zarplotter.h"
+#if MACHINE_STYLE == ZARPLOTTER
/**
* Inverse Kinematics turns XY coordinates into lengths of belt from each motor
* @param axies the cartesian coordinates
* @param motorStepArray a measure of each belt to that plotter position
*/
-void IK(float *cartesian, long *motorStepArray) {
+void IK(const float *const cartesian, long *motorStepArray) {
float limit_xmin = axies[0].limitMin;
float limit_xmax = axies[0].limitMax;
float limit_ymin = axies[1].limitMin;
diff --git a/robot_zarplotter.h b/robot_zarplotter.h
index a7bfda1..b3ac899 100644
--- a/robot_zarplotter.h
+++ b/robot_zarplotter.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
@@ -44,4 +43,3 @@
#endif // #ifndef ROBOT_ZARPLOTTER_H
-
diff --git a/sdcard.ino b/sdcard.cpp
similarity index 79%
rename from sdcard.ino
rename to sdcard.cpp
index e9b07ba..73d9f11 100644
--- a/sdcard.ino
+++ b/sdcard.cpp
@@ -1,13 +1,13 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// INCLUDES
//------------------------------------------------------------------------------
+#include "configure.h"
#include "sdcard.h"
#include
@@ -34,7 +34,7 @@ long sd_bytes_read;
//------------------------------------------------------------------------------
// initialize the SD card and print some info.
-void SD_init() {
+void SD_setup() {
#ifdef HAS_SD
pinMode(SDSS, OUTPUT);
pinMode(SDCARDDETECT,INPUT);
@@ -86,8 +86,11 @@ void SD_check() {
int c;
while(sd_print_file.peek() != -1) {
c=sd_print_file.read();
- serialBuffer[sofar++]=c;
sd_bytes_read++;
+ if(c=='\r') continue;
+ if(sofar.
- */
diff --git a/sdcard.h b/sdcard.h
index 4f730c3..409e7ce 100644
--- a/sdcard.h
+++ b/sdcard.h
@@ -3,8 +3,7 @@
//------------------------------------------------------------------------------
// Makelangelo - firmware for various robot kinematic models
// dan@marginallycelver.com 2013-12-26
-// Copyright at end of file. Please see
-// http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
+// Please see http://www.github.com/MarginallyClever/makelangeloFirmware for more information.
//------------------------------------------------------------------------------
@@ -20,5 +19,9 @@ extern char sd_printing_paused;
extern float sd_percent_complete;
#endif
+extern void SD_check();
+extern void SD_setup();
+extern void SD_listFiles();
+extern void SD_StartPrintingFile(const char *);
#endif // SDCARD_H