Ondertussen ook getest met de feed-override en de spindle-override knoppen: het werkt goed. Door één van de inputs op te offeren heb ik nu 8 outputs erbij gekregen. Zo kan ik een lampje laten branden zodra bijvoorbeeld de feed-hold is ingedrukt. Beetje user-feedback lijkt me wel handig (het hoeft natuurlijk ook weer geen Kerstboom te worden).
Arduino:
Code: Selecteer alles
#include <avdweb_AnalogReadFast.h>
#include <avdweb_Switch.h>
#include <Encoder.h>
#include <FastShiftOut.h>
#define VERSION_STRING "Imperator v1.0 Fighting Furiosa"
// The baudrate for communication with LinuxCNC. Should be equal to the baudrate defined in imperator.comp
#define BAUDRATE 9600
/*
* Definitions for the encoders. On the Arduino these pins must support interupts, on the Leonardo (Pro Micro) these
* pins are 0, 1, 2, and 3. Using any of these two pins will enable fast mode on the Encoder Library.
*
* NOTE: when using an older AtMega328 based boards (such as the Uno, Nano and clones), only pins 2 and 3 are supported.
*/
#define FAST_ENCODER_PIN_A 2
#define FAST_ENCODER_PIN_B 3
#define ENCODER1_PIN_A 0
#define ENCODER1_PIN_B 4
#define ENCODER2_PIN_A 1
#define ENCODER2_PIN_B 5
Encoder fastEncoder(FAST_ENCODER_PIN_A, FAST_ENCODER_PIN_B);
Encoder encoder1(ENCODER1_PIN_A, ENCODER1_PIN_B);
Encoder encoder2(ENCODER2_PIN_A, ENCODER2_PIN_B);
/*
* The rotary knobs for the axis have a resistor ladder, in order to minimize the number of inputs they use. Irrespective
* to the number of axis (XYZABC) and STEPS (0.1, 0.01, 0.001, etc), the knobs will only use a single, analog pin.
*/
#define AXIS_SELECTOR A3
#define AXIS_NUMBER 2 // The number of axis supported by this MPG. For a Lathe this will be 2, for a Mill this will be usually 3
#define STEP_SELECTOR A2
#define STEP_NUMBER 3 // The number of steps supported by this MPG, usually three steps is more then enough
/*
* Pins on which all switches are located. Although the numbering looks awkward, it corresponds with a counter clockwise numbering
* on the Arduino Pro Micro, with four pins on each side. The numbering of the pins on the board is not sequential.
*/
#define USER_SWITCH_0 6
#define USER_SWITCH_1 7
#define USER_SWITCH_2 8
#define USER_SWITCH_3 9
#define USER_SWITCH_4 10
#define USER_SWITCH_5 16
#define USER_SWITCH_6 14
//#define USER_SWITCH_7 15
/*
* Create an array with the above mentioned switches
*/
Switch userSwitches[] = {
Switch(USER_SWITCH_0),
Switch(USER_SWITCH_1),
Switch(USER_SWITCH_2),
Switch(USER_SWITCH_3),
Switch(USER_SWITCH_4),
Switch(USER_SWITCH_5),
Switch(USER_SWITCH_6),
// Switch(USER_SWITCH_7)
};
uint8_t userSwitchesLength = sizeof(userSwitches) / sizeof(userSwitches[0]);
uint8_t button_state = 0;
/*
* SHIFT REGISTER
* In order to give feedback to the user, up to 8 digital outputs can be created
*/
#define HC595_CLOCK 15
#define HC595_DATA 18
#define HC595_LATCH 19
FastShiftOut dataShifter = FastShiftOut(HC595_DATA, HC595_CLOCK);
/*
* This is data from the MPG is organized in a struct, which is later used to be send as an
* byteArray. This is useful for concatenating several variables into a single byte array
* to send over USB or any other protocol.
* In other words you have a fixed byte array, and we squeeze in variables of different
* data types and lengths into it, while still using it as a byte array afterwards.
*/
struct mpg_data_t {
int32_t fastEncoderCount;
int32_t encoder1Count;
int32_t encoder2Count;
uint8_t axis;
uint8_t step;
uint8_t button_state;
} ;
/*
* The way we use a union here (in plain terms) is: the union is a fixed region of memory that we
* can write to in one format (as a structure) and then read from in another format (a byte array).
* You can do it in reverse as well, write to it as a byte array, and read it as a structure.
*/
union usb_data_t {
mpg_data_t mpg;
uint8_t byteArray[sizeof(mpg_data_t)];
};
usb_data_t dataToSend;
// Enumerations of the state of the Toolerator
enum states {
initState,
listeningState,
queryState,
updateState,
versionState
} state;
void setup() {
// Listen on the serial port for tool change commands
Serial.begin(BAUDRATE);
// Hook up the buttons to the functions which store the state
userSwitches[0].setPushedCallback(&button0Pushed, NULL);
userSwitches[1].setPushedCallback(&button1Pushed, NULL);
userSwitches[2].setPushedCallback(&button2Pushed, NULL);
userSwitches[3].setPushedCallback(&button3Pushed, NULL);
userSwitches[4].setPushedCallback(&button4Pushed, NULL);
userSwitches[5].setPushedCallback(&button5Pushed, NULL);
userSwitches[6].setPushedCallback(&button6Pushed, NULL);
// userSwitches[7].setPushedCallback(&button7Pushed, NULL);
// Set the state to initial state;
state=initState;
}
void loop() {
// Check whether the component needs to initalize or communicate
switch(state) {
case initState:
handleInitState();
break;
case listeningState:
handleListeningState();
break;
case queryState:
handleQueryState();
break;
case updateState:
shiftDataOut();
break;
case versionState:
Serial.println(VERSION_STRING);
state=listeningState;
break;
}
// Poll the switches, required to get the state
for (uint8_t i = 0; i < userSwitchesLength; i++) {
userSwitches[i].poll();
}
}
/*
* This is the state which is enetered after initialisation of the Imperator. It
* will write a ready message o the Serial and put the state in listening model
*/
void handleInitState() {
// print "H" for HAL500--ready message
Serial.write('H');
// Start listening to commands
state=listeningState;
}
/*
* This function listens for commands over the USB. When a request is
* made, this will command HAL500 to report the state of the inputs.
*/
void handleListeningState() {
if (Serial.available() > 0) {
byte b = Serial.read(); // Read 1 byte from the buffer
switch(b) {
case 'Q':
state=queryState;
break;
case 'V':
state=versionState;
break;
case 'U':
state=updateState;
break;
default:
// Unknown command, report back and don't change the state
Serial.write('?');
break;
}
}
}
/*
* This is the state which will return the current MPG-count and the state of the
* switches to LinuxCNC
*/
void handleQueryState() {
// Send the struct over serial to LinuxCNC for further processing
dataToSend.mpg.fastEncoderCount = fastEncoder.read();
dataToSend.mpg.encoder1Count = encoder1.read();
dataToSend.mpg.encoder2Count = encoder2.read();
dataToSend.mpg.axis = parseLadder(AXIS_SELECTOR, AXIS_NUMBER);
dataToSend.mpg.step = parseLadder(STEP_SELECTOR, STEP_NUMBER);
dataToSend.mpg.button_state = button_state;
// Write the data over serial
Serial.write(dataToSend.byteArray, sizeof(mpg_data_t));
//for(int i=0; i < sizeof(mpg_data_t); i++) {
// Serial.print(dataToSend.byteArray[i]);
//}
// Reset the button state
button_state = 0;
// Return to listen to commands
state=listeningState;
}
/*
* This function shofts the received data out to the latch
*/
void shiftDataOut() {
if (Serial.available() > 0) {
// Read one byte from the buffer
uint8_t data = Serial.read(); // Read 1 byte from the buffer
// Shift the data out using the 74HC595
digitalWrite(HC595_LATCH, LOW);
dataShifter.writeLSBFIRST(data);
digitalWrite(HC595_LATCH, HIGH);
// Return to listen to commands
state=listeningState;
}
}
/**
* This function parses the value from the resistor ladder. All possible ADC values (1024) are
* divided in bins and then processed.
*/
uint8_t parseLadder(uint8_t pin, uint8_t bins) {
// Read the value from the analog
uint16_t analog = analogReadFast(pin);
// Divide the maximum value from the analog into the bin sizes. The first
// bin ends at half the size of a bin.
uint16_t bin_size = 1024 / (bins - 1);
// Determine in which bin the value falls
uint8_t result = 0;
for (uint16_t bin_end = bin_size >> 1; bin_end <= 1024; bin_end += bin_size) {
result++;
if (analog < bin_end) {
return result;
}
}
return result;
}
/*
* Callbacks for when a button is pushed by the end-user.
*/
void button0Pushed(void* ref) {
button_state |= (1 << 0);
}
void button1Pushed(void* ref) {
button_state |= (1 << 1);
}
void button2Pushed(void* ref) {
button_state |= (1 << 2);
}
void button3Pushed(void* ref) {
button_state |= (1 << 3);
}
void button4Pushed(void* ref) {
button_state |= (1 << 4);
}
void button5Pushed(void* ref) {
button_state |= (1 << 5);
}
void button6Pushed(void* ref) {
button_state |= (1 << 6);
}
void button7Pushed(void* ref) {
button_state |= (1 << 7);
}
Ik zal straks van de machine het HAL-component afhalen en delen.
Assumptions are the mother of all $%^& ups.
Twee keer meten is zeker weten, als je weet wat je meet...