labrobot/otto/otto.ino
2021-05-31 22:27:33 +02:00

725 lines
21 KiB
C++

/*
* Author David Florian
* Simplified G-code interpreter
*
* If you decide not to implement optional features you must
* comment out the correspondin
* g blocks of code
*/
#define jfs
#ifdef otto
#include <TMCStepper.h>
#endif
//**** ARDUINO PINS *****
//***** X-Axis *****
#ifdef otto
#define X_EN_PIN 22 // Enable
#define X_STEP_PIN 23 // Step
#define X_DIR_PIN 24 // Direction
#define X_CS_PIN 25 // Chip select
#define X_LIMIT 41 // Limit Switch
#else
#define X_STEP_PIN 54
#define X_DIR_PIN 55
#define X_EN_PIN 38
#define X_CS_PIN 53 // EXP2_07_PIN
#define X_LIMIT 3 // X_MIN_PIN
#endif
//***** Y-Axis *****
#ifdef otto
#define Y_EN_PIN 26 // Enable
#define Y_STEP_PIN 27 // Step
#define Y_DIR_PIN 29 // Direction
#define Y1_CS_PIN 28 // Chip select
#define Y2_CS_PIN 30 // Chip select
#define Y_LIMIT 42 // Limit Switch
#else
#define Y_EN_PIN 56 // Enable
#define Y_STEP_PIN 60 // Step
#define Y_DIR_PIN 61 // Direction
#define Y1_CS_PIN 49 // EXP2_04_PIN
#define Y2_CS_PIN 49 // ???
#define Y_LIMIT 14 // Y_MIN_PIN
#endif
//***** Z-Axis *****
#ifdef otto
#define Z_EN_PIN 31 // Enable
#define Z_STEP_PIN 32 // Step
#define Z_DIR_PIN 33 // Direction
#define Z_CS_PIN 34 // Chip select
#define Z_LIMIT 45 // Limit Switch
#else
#define Z_EN_PIN 62 // Enable
#define Z_STEP_PIN 46 // Step
#define Z_DIR_PIN 48 // Direction
#define Z_CS_PIN 40 // Chip select
#define Z_LIMIT 18 // Z_MIN_PIN
#endif
//***** P-Axis *****
#ifdef otto
#define P_EN_PIN 62 // Enable
#define P_STEP_PIN 36 // Step
#define P_DIR_PIN 37 // Direction
#define P_CS_PIN 38 // Chip select
#else
#define P_EN_PIN 24 // E0_ENABLE_PIN
#define P_STEP_PIN 26 // E0_STEP_PIN
#define P_DIR_PIN 28 // E0_DIR_PIN
#define P_CS_PIN 42 // E0_CS_PIN
#endif
//***** Floating Head *****
#define FLOATING_HEAD 47 // Floating Head Switch
//***** Tip Sensors *****
#define X_LASER 44 // Yellow
#define Y_LASER 40 // Black
//***** Optional LEDs ******
#define LED_SKIRT 5
#define LED_Pipette 4
//***** Optional Buttons *****
#define PLAY_PAUSE_BUTTON 50
#define PLAY_PAUSE_LED 2 // The LEDs in the button can be turned on and off
#define ALERT_BUTTON 46
#define ALERT_BUTTON_LED 3 // The LEDs in the button can be turned on and off
#ifdef otto
//**** STEPPER DRIVERS *****
//***** Configuring TMC2660 Stepper drivers *****
#define R_SENSE 0.1f // Match to your driver
// SilentStepStick series use 0.11
// UltiMachine Einsy and Archim2 boards use 0.2
// Panucatt BSD2660 uses 0.1
// Watterott TMC5160 uses 0.075
TMC2660Stepper driverX = TMC2660Stepper(X_CS_PIN, R_SENSE);
TMC2660Stepper driverY1 = TMC2660Stepper(Y1_CS_PIN, R_SENSE);
TMC2660Stepper driverY2 = TMC2660Stepper(Y2_CS_PIN, R_SENSE);
TMC2660Stepper driverZ = TMC2660Stepper(Z_CS_PIN, R_SENSE);
TMC2660Stepper driverP = TMC2660Stepper(P_CS_PIN, R_SENSE);
#endif
#ifdef jfs
#define motorInterfaceType 1
#endif
//***** Configuring Step/Dir Pins with AccelStepper *****
#include <AccelStepper.h>
#include <MultiStepper.h>
#ifdef otto
AccelStepper stepperX(AccelStepper::DRIVER, X_STEP_PIN, X_DIR_PIN);
AccelStepper stepperY(AccelStepper::DRIVER, Y_STEP_PIN, Y_DIR_PIN);
AccelStepper stepperZ(AccelStepper::DRIVER, Z_STEP_PIN, Z_DIR_PIN);
AccelStepper stepperP(AccelStepper::DRIVER, P_STEP_PIN, P_DIR_PIN);
#endif
#ifdef jfs
AccelStepper stepperX = AccelStepper(motorInterfaceType, X_STEP_PIN, X_DIR_PIN);
AccelStepper stepperY = AccelStepper(motorInterfaceType, Y_STEP_PIN, Y_DIR_PIN);
AccelStepper stepperZ = AccelStepper(motorInterfaceType, Z_STEP_PIN, Z_DIR_PIN);
AccelStepper stepperP = AccelStepper(motorInterfaceType, P_STEP_PIN, P_DIR_PIN);
#endif
#ifdef otto
//***** OPTIONAL LEDs CONFIGURATION *****
#include <Adafruit_NeoPixel.h> //These are WS2812 LEDs AKA Neopixels
int skirt_leds_num = 14; //Number of LEDs per strip
int pipette_leds_num = 8;
Adafruit_NeoPixel skirt_leds = Adafruit_NeoPixel(skirt_leds_num, LED_SKIRT, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pipette_leds = Adafruit_NeoPixel(pipette_leds_num, LED_Pipette, NEO_GRB + NEO_KHZ800);
#endif
int changeDirection = 1;
// ***** Variables for Serial Communication with Computer *****
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
// variables to hold the parsed data
char mode[6];
int integerFromPC = 0;
float floatFromPC = 0.0;
boolean newData = false;
//***** Limit Switches *****
//variables to hold the limit switch states
boolean homeX;
boolean homeY;
boolean homeZ;
boolean homeP;
//***** STEP PER MM *****
//Its important that these values are correct
//so that the digital coordinate system = matches real world
//Total step per revolution = full steps/rev * microsteps
//200 full steps * 16 microsteps = 3200 digital steps
int x_steps_mm = 80;
int y_steps_mm = 80;
int z_steps_mm = 80;
int p_steps_mm = 157.5;
// variables to hold location data
double locX_in_mm;
double locY_in_mm;
double locZ_in_mm;
double locP_in_mm;
int locX_in_steps;
int locY_in_steps;
int locZ_in_steps;
int locP_in_steps;
#ifdef jfs
int locX_max = 27000;
int locY_max = -31200;
int locZ_max = 4400;
#endif
// variables to hold LED data
int ledR;
int ledG;
int ledB;
void setup() {
#ifdef otto
SPI.begin();
#endif
Serial.begin(9600);
while(!Serial);
#ifdef otto
// Outputs for Chip Select (or SS) SPI Communication
pinMode(X_CS_PIN, OUTPUT);
pinMode(Y1_CS_PIN, OUTPUT);
pinMode(Y2_CS_PIN, OUTPUT);
pinMode(Z_CS_PIN, OUTPUT);
pinMode(P_CS_PIN, OUTPUT);
digitalWrite(X_CS_PIN, HIGH);
digitalWrite(Y1_CS_PIN, HIGH);
digitalWrite(Y2_CS_PIN, HIGH);
digitalWrite(Z_CS_PIN, HIGH);
digitalWrite(P_CS_PIN, HIGH);
#endif
//***** Setting up Drivers *****
#ifdef otto
// X-axis Driver
driverX.begin(); // Initiate pins and registeries
driverX.rms_current(1000); // Set stepper current to 600mA.
driverX.microsteps(16);
delay(100);
// Y-axis Driver 1
driverY1.begin(); // Initiate pins and registeries
driverY1.rms_current(1000); // Set stepper current to 600mA.
driverY1.microsteps(16);
delay(100);
// Y-axis Driver 2
driverY2.begin(); // Initiate pins and registeries
driverY2.rms_current(1000); // Set stepper current to 600mA.
driverY2.microsteps(16);
delay(100);
// Z-axis Driver
driverZ.begin(); // Initiate pins and registeries
driverZ.rms_current(400); // Set stepper current to 600mA.
driverZ.microsteps(16);
delay(100);
// P-axis Driver
driverP.begin(); // Initiate pins and registeries
driverP.rms_current(400); // Set stepper current to 600mA.
driverP.microsteps(4);
delay(100);
#endif
//***** Setting up Switches, Sensors, and Buttons *****
pinMode(X_LIMIT, INPUT);
pinMode(Y_LIMIT, INPUT);
pinMode(Z_LIMIT, INPUT);
pinMode(FLOATING_HEAD, INPUT);
pinMode(X_LASER, INPUT);
pinMode(Y_LASER, INPUT);
pinMode(PLAY_PAUSE_BUTTON, INPUT);
pinMode(PLAY_PAUSE_LED, OUTPUT);
digitalWrite(PLAY_PAUSE_LED, LOW);
pinMode(ALERT_BUTTON, INPUT);
pinMode(ALERT_BUTTON_LED, OUTPUT);
digitalWrite(ALERT_BUTTON_LED, LOW);
stepperX.setMaxSpeed(15000); // 100mm/s @ 160 steps/mm
stepperX.setAcceleration(10000); // 2000mm/s^2
stepperX.setEnablePin(X_EN_PIN);
stepperX.setPinsInverted(false, false, true); // (directionInvert, stepInvert, enableInvert)
stepperX.enableOutputs();
stepperY.setMaxSpeed(12000); // 100mm/s @ 80 steps/mm
stepperY.setAcceleration(8000); // 2000mm/s^2
stepperY.setEnablePin(Y_EN_PIN);
stepperY.setPinsInverted(false, false, true); // (directionInvert, stepInvert, enableInvert)
stepperY.enableOutputs();
stepperZ.setMaxSpeed(12000); // 100mm/s @ 80 steps/mm
stepperZ.setAcceleration(7000); // 2000mm/s^2
stepperZ.setEnablePin(Z_EN_PIN);
stepperZ.setPinsInverted(false, false, true); // (directionInvert, stepInvert, enableInvert)
stepperZ.enableOutputs();
stepperP.setMaxSpeed(5000); // 100mm/s @ 80 steps/mm
stepperP.setAcceleration(1000); // 2000mm/s^2
stepperP.setEnablePin(P_EN_PIN);
stepperP.setPinsInverted(true, false, true); // (directionInvert, stepInvert, enableInvert)
stepperP.enableOutputs();
#ifdef jfs
pinMode(X_EN_PIN, OUTPUT); // Enable
digitalWrite(X_EN_PIN,LOW);
pinMode(Y_EN_PIN, OUTPUT); // Enable
digitalWrite(Y_EN_PIN,LOW);
pinMode(Z_EN_PIN, OUTPUT); // Enable
digitalWrite(Z_EN_PIN,LOW);
#endif
#ifdef otto
//***** Turn on LEDs *****
skirt_leds.begin();
for(int i=0;i<skirt_leds_num;i++){
// skirt_leds.Color takes RGB values, from 0,0,0 up to 255,255,255
skirt_leds.setPixelColor(i, skirt_leds.Color(50,50,50)); // red
skirt_leds.show(); // This sends the updated pixel color to the hardware.
}
pipette_leds.begin();
for(int i=0;i<pipette_leds_num;i++){
// skirt_leds.Color takes RGB values, from 0,0,0 up to 255,255,255
pipette_leds.setPixelColor(i, pipette_leds.Color(100,100,100)); // red
pipette_leds.show(); // This sends the updated pixel color to the hardware.
}
#endif
}
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
Serial.println(tempChars);
parseData();
coordinateMove();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
//***** Poll the current location of the stepper motors *****
locX_in_mm = stepperX.currentPosition() / x_steps_mm;
locY_in_mm = stepperY.currentPosition() / y_steps_mm;
locZ_in_mm = stepperZ.currentPosition() / z_steps_mm;
locP_in_mm = stepperP.currentPosition() / p_steps_mm;
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars," ");
strcpy(mode, strtokIndx);
strtokIndx = strtok(NULL," ");
while (strtokIndx != NULL){
if (strtokIndx[0] == 'X'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
locX_in_mm = atof(strtokIndx);
}
if (strtokIndx[0] == 'Y'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
locY_in_mm = -atof(strtokIndx);
}
if (strtokIndx[0] == 'Z'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
locZ_in_mm = atof(strtokIndx);
}
if (strtokIndx[0] == 'P'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
locP_in_mm = atof(strtokIndx);
}
if (strtokIndx[0] == 'E'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
locP_in_mm = atof(strtokIndx);
}
if (strtokIndx[0] == 'R'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
ledR = atoi(strtokIndx);
}
if (strtokIndx[0] == 'U' || strtokIndx[0] == 'G'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
ledG = atoi(strtokIndx);
}
if (strtokIndx[0] == 'B'){
memmove(strtokIndx, strtokIndx+1, strlen(strtokIndx));
ledB = atoi(strtokIndx);
}
strtokIndx = strtok (NULL, " ");
}
//***** mm to steps conversions *****
locX_in_steps = locX_in_mm * x_steps_mm;
#ifdef jfs
if (locX_in_steps > locX_max) {
Serial.println(" X off limits ");
locX_in_steps = locX_max;
}
#endif
locY_in_steps = locY_in_mm * y_steps_mm;
#ifdef jfs
if (locY_in_steps < locY_max) {
Serial.println(" Y off limits ");
locY_in_steps = locY_max;
}
#endif
locZ_in_steps = locZ_in_mm * z_steps_mm;
#ifdef jfs
if (locZ_in_steps > locZ_max) {
Serial.println(" Z off limits ");
locZ_in_steps = locZ_max;
}
#endif
locP_in_steps = locP_in_mm * p_steps_mm;
}
//============
void coordinateMove(){
stepperX.setMaxSpeed(2000);
stepperX.setAcceleration(1000);
stepperY.setMaxSpeed(2000);
stepperY.setAcceleration(1000);
stepperZ.setMaxSpeed(2000);
stepperZ.setAcceleration(1000);
if (strcmp(mode, "G1") == 0){
stepperX.moveTo(locX_in_steps);
stepperY.moveTo(locY_in_steps);
stepperZ.moveTo(locZ_in_steps);
stepperP.moveTo(locP_in_steps);
stepperX.setMaxSpeed(10000);
stepperX.setAcceleration(3000);
stepperY.setMaxSpeed(10000);
stepperY.setAcceleration(4000);
stepperZ.setMaxSpeed(10000);
stepperZ.setAcceleration(6000);
stepperP.setMaxSpeed(12000);
stepperP.setAcceleration(6000);
while(stepperX.targetPosition() != stepperX.currentPosition() or stepperY.targetPosition() != stepperY.currentPosition() or stepperZ.targetPosition() != stepperZ.currentPosition() or stepperP.targetPosition() != stepperP.currentPosition()){
stepperX.run();
stepperY.run();
stepperZ.run();
stepperP.run();
delay(0.001);
}
Serial.println("<ok>");
}
#ifdef otto
//***** M150 - Change LED Color *****
else if (strcmp(mode, "M150") == 0){
for(int i=0;i<skirt_leds_num;i++){
// skirt_leds.Color takes RGB values, from 0,0,0 up to 255,255,255
skirt_leds.setPixelColor(i, skirt_leds.Color(ledR,ledG,ledB)); // red
skirt_leds.show(); // This sends the updated pixel color to the hardware.
}
for(int i=0;i<pipette_leds_num;i++){
// skirt_leds.Color takes RGB values, from 0,0,0 up to 255,255,255
pipette_leds.setPixelColor(i, pipette_leds.Color(ledR,ledG,ledB)); // red
pipette_leds.show(); // This sends the updated pixel color to the hardware.
}
Serial.println("<ok>");
}
#endif
//***** M1001 - Laser/Mechanical probing of tip *****
else if (strcmp(mode, "M1001") == 0){
//Speeds and accelerations for tip probe move
stepperX.setMaxSpeed(5000);
stepperX.setAcceleration(2000);
stepperY.setMaxSpeed(5000);
stepperY.setAcceleration(2000);
stepperZ.setMaxSpeed(5000);
stepperZ.setAcceleration(500);
boolean boolX = false;
boolean tipcheckX = false;
boolean tipcheckY = false;
int coordX = stepperX.currentPosition();
int coordY = stepperY.currentPosition();
int coordXafter;
int coordYafter;
int laserXmove = coordX - 1600; //Take the current X position and move 1600 steps (20mm) in the -X direction
int laserYmove = coordY + 8000; //Take the current Y position and move 8000 steps (20mm) in the +Y direction
//Move in the -X direction until laser tripped
stepperX.moveTo(laserXmove);
Serial.println(stepperX.distanceToGo());
while (boolX == false && stepperX.distanceToGo()!=0) {
stepperX.run();
if (digitalRead(X_LASER) != 0){
delay(10);
if (digitalRead(X_LASER) != 0){
boolX= true;
stepperX.setSpeed(0);
coordXafter = stepperX.currentPosition();
stepperX.move(400); //Move 5mm in the X+ direction. Now the pipette tip will be aligned with the tip that was used during the calibration on the motion controller screen.
tipcheckX = true;
}
}
}
if (tipcheckX == false){
stepperX.move(1600);
}
//Move back to the X starting point
while(stepperX.targetPosition() != stepperX.currentPosition()){
stepperX.run();
}
//Move up 10mm because the Y laser is higher
stepperZ.move(4000);
while(stepperZ.targetPosition() != stepperZ.currentPosition()){
stepperZ.run();
}
boolean boolY = false;
stepperY.moveTo(laserYmove);
while (boolY == false && stepperY.distanceToGo()!=0) {
stepperY.run();
if (digitalRead(Y_LASER) != 0){
delay(10);
if (digitalRead(Y_LASER) != 0){
boolY= true;
stepperY.setSpeed(0);
Serial.println(stepperY.distanceToGo());
coordYafter = stepperY.currentPosition();
stepperY.move(-2000); //Move 5mm in the Y- direction. Now the pipette tip will be aligned with the tip that was used during the calibration on the motion controller screen.
tipcheckY = true;
}
}
}
if (tipcheckY == false){
stepperY.move(-8000);
}
stepperZ.move(-4000);
while(stepperY.targetPosition() != stepperY.currentPosition() or stepperZ.targetPosition() != stepperZ.currentPosition()){
stepperY.run();
stepperZ.run();
}
if (tipcheckY == false || tipcheckX == false){
Serial.println("<no>");
}
else{
Serial.println("<ok>");
}
}
else if (strcmp(mode, "J2") == 0){
Serial.print("X Position ");
Serial.println( stepperX.currentPosition());
Serial.print("Y Position ");
Serial.println( stepperY.currentPosition());
Serial.print("Z Position ");
Serial.println( stepperZ.currentPosition());
}
else if (strcmp(mode, "JZ") == 0){
//Homing Z at min
stepperZ.setMaxSpeed(5000);
stepperZ.setAcceleration(2000);
int initial_homing = stepperZ.currentPosition();
homeZ = false;
while (homeZ == false){
initial_homing--;
stepperZ.moveTo(initial_homing);
stepperZ.run();
if (digitalRead(Z_LIMIT) != 1) {
delay(1);
if (digitalRead(Z_LIMIT) !=1){
homeZ = true;
}
}
}
stepperZ.setMaxSpeed(10000);
stepperZ.setAcceleration(5000);
stepperZ.setCurrentPosition(0);
stepperP.setCurrentPosition(0);
Serial.println("<Z Homed>");
}
//***** G28 - Homing Cycle *****
// For this code to work as written the limit switches must be located at
// X - Mininum
// Y - Minimun
// Z - Minimun
else if (strcmp(mode, "G28") == 0){
//Homing X at min
stepperX.setMaxSpeed(5000);
stepperX.setAcceleration(2000);
int initial_homing = stepperX.currentPosition();
homeX = false;
while (homeX == false){
initial_homing--;
stepperX.moveTo(initial_homing);
stepperX.run();
if (digitalRead(X_LIMIT) != 1) {
delay(1);
if (digitalRead(X_LIMIT) !=1){
homeX = true;
}
}
}
stepperX.setMaxSpeed(10000);
stepperX.setAcceleration(5000);
stepperX.setCurrentPosition(0);
//Homing Y at min
stepperY.setMaxSpeed(5000);
stepperY.setAcceleration(2000);
initial_homing = stepperY.currentPosition();
homeY = false;
while (homeY == false){
initial_homing++;
stepperY.moveTo(initial_homing);
stepperY.run();
if (digitalRead(Y_LIMIT) != 1) {
delay(1);
if (digitalRead(Y_LIMIT) !=1){
homeY = true;
}
}
}
stepperY.setMaxSpeed(10000);
stepperY.setAcceleration(5000);
stepperY.setCurrentPosition(0);
//Homing Z at min
stepperZ.setMaxSpeed(5000);
stepperZ.setAcceleration(2000);
initial_homing = stepperZ.currentPosition();
homeZ = false;
while (homeZ == false){
initial_homing--;
stepperZ.moveTo(initial_homing);
stepperZ.run();
if (digitalRead(Z_LIMIT) != 1) {
delay(1);
if (digitalRead(Z_LIMIT) !=1){
homeZ = true;
}
}
}
stepperZ.setMaxSpeed(10000);
stepperZ.setAcceleration(5000);
stepperZ.setCurrentPosition(0);
stepperP.setCurrentPosition(0);
Serial.println("<OK Homed>");
}
//########Grab Tip#########
else if (strcmp(mode, "G38") == 0){
//Move down until Floating head limit switch is triggered
//The limit switch trig is debounced (50ms)
int tipStatus = 0;
int tipStepCount = stepperZ.currentPosition();
int positionBeforeTip = stepperZ.currentPosition();
stepperZ.setMaxSpeed(6000);
stepperZ.setAcceleration(2000);
while (tipStatus == 0){
if (digitalRead(FLOATING_HEAD) != 0){
stepperZ.setSpeed(0);
stepperZ.moveTo(stepperZ.currentPosition());
tipStatus = 1;
}
else {
tipStepCount--;
stepperZ.moveTo(tipStepCount);
}
stepperZ.run();
}
stepperZ.moveTo(positionBeforeTip);
while(stepperZ.targetPosition() != stepperZ.currentPosition()){
stepperZ.run();
}
Serial.println("<ok>");
}
}