Skip to content

Instantly share code, notes, and snippets.

@jmcgill
Last active January 4, 2023 03:18
Show Gist options
  • Save jmcgill/0e94826c0ee0ed38971d6d2df80b825c to your computer and use it in GitHub Desktop.
Save jmcgill/0e94826c0ee0ed38971d6d2df80b825c to your computer and use it in GitHub Desktop.
Code for Arduino based CNC Controller
#include <Keyboard.h>
#include <EEPROM.h>
#include <Encoder.h>
int CENTER = 0;
int UP = 1;
int DOWN = 2;
int LEFT = 3;
int RIGHT = 4;
char buffer[50];
char *dirs[] = { "CENTER", "UP", "DOWN", "LEFT", "RIGHT" };
char *modes[] = { "CORNER", "CENTER", "???", "SLOW JOG", "MEDIUM JOG", "FAST JOG" };
char dirKeys[] = {'C', 'U', 'D', 'L', 'R'};
char jogKeys[] = {'C', KEY_UP_ARROW, KEY_DOWN_ARROW, KEY_LEFT_ARROW, KEY_RIGHT_ARROW};
char modeKeys[] = {'1', '2', '3', '4', '5', '6'};
unsigned long lastDirectionSent = 0;
int direction = CENTER;
int lastDirection = CENTER;
int buttonValues[10];
int lastMode = -1;
int mode = -1;
unsigned long buttonTimers[12];
// Pins 0 and 1 are used for the Z-Axis encoder
Encoder knob(0, 1);
long encoderPosition = -999;
// long lastSentPosition = -999;
int encoderDirection = CENTER;
int lastEncoderDirection = CENTER;
unsigned long encoderTimer = 0;
void sendCode(char code) {
sprintf(buffer, "Sending code %c\n", code);
Serial.print(buffer);
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(code);
delay(100);
Keyboard.releaseAll();
}
void setup() {
// Pins 2 through 7 are used for the rotary selector switch
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
// Pins 8 and 9 are used for Start / Stop
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
// Home No Z
pinMode(14, INPUT_PULLUP);
// Ref All Home No Z Button
pinMode(15, INPUT_PULLUP);
// Auto Tool Zero
pinMode(16, INPUT_PULLUP);
// Ref All Home Button
pinMode(18, INPUT_PULLUP);
pinMode(19, INPUT_PULLUP);
// Spindle Toggle
pinMode(10, INPUT_PULLUP);
// Read mode
// mode = EEPROM.read(0);
}
int getMode() {
for (int i = 2; i < 8; ++i) {
int val = digitalRead(i);
if (val == 0) {
return i - 2;
}
}
}
int pinMappings[] = {
14,
15,
16,
19,
10,
8,
9,
};
int risingEdgeWithDebounce(int index) {
int value = digitalRead(pinMappings[index]);
if ((millis() - buttonTimers[index]) > 200) {
if (value == 0) {
if (buttonValues[index] == 1) {
buttonTimers[index] = millis();
buttonValues[index] = 0;
return 1;
}
}
if (value == 1) {
if (buttonValues[index] == 0) {
buttonTimers[index] = millis();
buttonValues[index] = 1;
}
}
}
return 0;
}
void sendSpecialCommand(int i) {
if (i == 0) {
// Go to CNC zero
Serial.print("Moving X,Y to CNC Zero\n");
sendCode('7');
} else if (i == 1) {
// Set current X,Y = 0
Serial.print("Zero X & Y\n");
sendCode('Q');
sendCode('E');
} else if (i == 2) {
// Home No Z
Serial.print("Home No Z\n");
sendCode('8');
} else if (i == 3) {
// Auto Tool Zero
Serial.print("Auto Tool 0\n");
sendCode('0');
} else if (i == 4) {
// Spindle Toggle
Serial.print("Toggle Spindle\n");
sendCode('S');
} else if (i == 5) {
// Start
Serial.print("Starting");
Keyboard.press(KEY_LEFT_ALT);
Keyboard.press('r');
delay(100);
Keyboard.releaseAll();
} else if (i == 6) {
// Stop / Pause
Serial.print("Pausing");
Keyboard.print(' ');
}
}
void loop() {
// Buttons
for (int i = 0; i < 7; ++i) {
if (risingEdgeWithDebounce(i)) {
sendSpecialCommand(i);
}
}
// Check rotary encoder
long newEncoderPosition;
newEncoderPosition = knob.read();
if (newEncoderPosition != encoderPosition) {
Serial.print(newEncoderPosition);
Serial.print(' ');
if (newEncoderPosition > encoderPosition) {
encoderDirection = UP;
} else {
encoderDirection = DOWN;
}
if (encoderDirection != lastEncoderDirection) {
Keyboard.releaseAll();
sendCode(modeKeys[3]);
if (encoderDirection == UP) {
Serial.print("Z UP");
Keyboard.press(KEY_PAGE_UP);
} else {
Serial.print("Z DOWN");
Keyboard.press(KEY_PAGE_DOWN);
}
lastEncoderDirection = encoderDirection;
}
encoderTimer = millis();
encoderPosition = newEncoderPosition;
}
// If we haven't seen any action in 100 mS then pause
if (millis() - encoderTimer > 250 && lastEncoderDirection != CENTER) {
Serial.print("Releasing Z\n");
Keyboard.releaseAll();
lastEncoderDirection = CENTER;
}
// Read the value of the rotary selector
mode = getMode();
if (mode != lastMode) {
Serial.print("Setting mode to: ");
Serial.print(modes[mode]);
Serial.print("\n");
// EEPROM.write(0, mode);
sendCode(modeKeys[mode]);
lastMode = mode;
}
// Read the value of the joystick, with maximum of one command
// sent per second.
int y = analogRead(A2);
int x = analogRead(A3);
if (x > 1000) {
direction = RIGHT;
} else if (x < 10) {
direction = LEFT;
} else if (y > 1000) {
direction = DOWN;
} else if (y < 10) {
direction = UP;
} else {
direction = CENTER;
}
if (mode < 3) {
if (direction != lastDirection || (millis() - lastDirectionSent) > 1000) {
lastDirectionSent = millis();
lastDirection = direction;
// Don't send center keycodes
if (direction != CENTER) {
//if (mode < 3) {
// We send the mode before every direction keypress to ensure
// that the mode in Mach3 always matches the mode on the control box.
sendCode(modeKeys[mode]);
sendCode(dirKeys[direction]);
//} else {
// sendCode(jogKeys[direction]);
//}
}
}
} else {
if (direction != lastDirection) {
sprintf(buffer, "Releasing arrow keys\n");
Serial.print(buffer);
Keyboard.releaseAll();
if (direction != CENTER ) {
sprintf(buffer, "Sending direction key %s\n", dirs[direction]);
Serial.print(buffer);
sendCode(modeKeys[mode]);
Keyboard.press(jogKeys[direction]);
}
}
lastDirection = direction;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment