Getting Back Up To Speed
It appears as though the code is waiting to be testing.
It has been a long time so I need to review what I have written.
Serial Initialisation
The initialisation of the serial interface is always tricky with the Arduino, here is my code:
// Indicate ready
Serial.begin(9600);
while (!Serial);
Serial.println("Motion Control V1.0");
Serial.flush();
The first line is pretty standard and for this application I don't want to go any faster than 9600 baud. The motion controller is pretty processor intensive so not a great idea to sent data too quickly.
The second line is almost essential on Linux PCs (no so much on Windows PCs). Without this line the first serial print is often (i.e. always) garbled. Basically the code has to wait until the Serial system is ready. On Windows PCs a 200 ms wait seems to work better.
The function of flush() as changed over time but at the moment it just waits until the output has been sent. It has no function on the input. In the past I would calculate the required delay for the text length to ensure that the serial has been sent before continuing. Why wait? If you send too much data and overflow the buffer then data will be lost.
For "gCodeSender" the ready message needs to be modifed to something like:
Serial.println("Grbl v0.1a");
Flow Control
In "Not GRBL" I used software handshakes (i.e. XON/XOFF) as I could only process one command at a time. With a ring buffer I should be able to use the "ok" protocol.
The variable "okay" is incremented upon completion of the motion (in the motion control ISR):
...
steps--;
if (steps==0) okay++;
...
and decremented each time it is printed to the serial port (in the main loop):
void loop()
{
// Flow control
if (okay>0) {
Serial.println("ok");
cli();okay--;sei();
}
}
Serial Event
I am using serialEvent() to decode the gCode and save the "primative" comands to the ring buffer. It is fairly complicated:
- Clean up the command string
- Decode the motion commands
- Push motion commands onto stack (not checked if the stack is full)
- Decode immediate commands
void serialEvent()
{
// Rember between calls
static long xNext=0;
static long yNext=0;
static long zNext=0;
static long fNext=Feed;
// Reset upon each call
long mNext=-1;
bool set=false;
long fQuery;
long xQuery;
long yQuery;
long zQuery;
long nQuery;
char inData[63];
int bRead;
// Get command string
bRead=Serial.readBytesUntil('\n',inData,63);
if (bRead>1) {
bRead--;
inData[bRead]='\0'; // End of string
// Clean up command string
for (int i=0;i<bRead;i++) {
// To upper case
if ((inData[i]>='a')&&(inData[i]<='z')) inData[i]-=32;
if ((inData[i]>='0')&&(inData[i]<='9')) {
// Integer numbers
} else if (inData[i]=='-') {
// Sign
} else if (inData[i]=='.') {
// Decimal
} else if (inData[i]=='?') {
// Ready
} else if (inData[i]=='X') {
// X axis movement
} else if (inData[i]=='Y') {
// Y axis movement
} else if (inData[i]=='Z') {
// Z axis movement
} else if (inData[i]=='F') {
// Feed rate
} else if (inData[i]=='M') {
// M Code
} else if (inData[i]=='$') {
// Status
} else if (inData[i]=='!') {
// Pause
} else if (inData[i]=='~') {
// Resume
} else if (inData[i]=='@') {
// Set current position as origin
} else {
// Clear character
inData[i]=' ';
}
}
// Decode motion commands
for (int i=0;i<bRead;i++) {
if (inData[i]=='X') {
xNext=(long)(atof(inData+i+1)*xStepsPerMM);
set=true;
} else if (inData[i]=='Y') {
yNext=(long)(atof(inData+i+1)*yStepsPerMM);
set=true;
} else if (inData[i]=='Z') {
zNext=(long)(atof(inData+i+1)*zStepsPerMM);
set=true;
} else if (inData[i]=='F') {
fNext=atol(inData+i+1);
if (fNext<1) fNext=1;
if (fNext>4095) fNext=4095;
set=true;
} else if (inData[i]=='M') {
mNext=atol(inData+i+1);
set=true;
}
}
// Push motion commands onto stack (no check if full)
if (set) {
// Push must not be interrupted
cli();
// Psuedo M-Codes
if ((mNext==2)||(mNext==30)) {
// Go Home (predefined)
if (Spindle<8) PORTD&=~(1<<Spindle); else if (Spindle<14) PORTB&=~(1<<Spindle-8);
xNew[head]=xCurrent;
yNew[head]=yCurrent;
zNew[head]=zHome*zStepsPerMM;
mCode[head]=mNext;
feed[head]=Feed;
if (++head>=stackSize) head=head-stackSize;
xNext=xHome*xStepsPerMM;
yNext=yHome*yStepsPerMM;
zNext=zCurrent;
mNext=mNext;
fNext=Feed;
}
xNew[head]=xNext;
yNew[head]=yNext;
zNew[head]=zNext;
feed[head]=fNext;
mCode[head]=mNext;
if (++head>=stackSize) head=head-stackSize;
sei();
}
// Decode immediate commands
for (int i=0;i<bRead;i++) {
if (inData[i]=='?') {
// Return queue length (used for flow control)
Serial.flush();
queue=head-tail;
if (queue<0) queue=queue+stackSize;
Serial.println(queue);
} else if (inData[i]=='$') {
// Return motion control status
if ((steps==0)||(paused)) {
cli();
nQuery=steps;
xQuery=xCurrent;
yQuery=yCurrent;
zQuery=zCurrent;
fQuery=fCurrent;
sei();
Serial.flush();
if (paused) {
Serial.println("$Paused");
} else {
if (steps>0) {
Serial.println("$Running");
} else {
Serial.println("$Stopped");
}
}
Serial.print("$Queue ");Serial.println(queue);
Serial.print("$Steps ");Serial.println(nQuery);
Serial.print("$Feed ");Serial.println(fQuery);
Serial.flush();
Serial.print("$X ");Serial.println(xQuery);
Serial.print("$Y ");Serial.println(yQuery);
Serial.print("$Z ");Serial.println(zQuery);
}
} else if (inData[i]=='!') {
// Pause motion
paused=true;
} else if (inData[i]=='~') {
// Resume motion
paused=false;
} else if (inData[i]=='@') {
// Reset as axes origin
if ((steps==0)||(paused)) {
cli();
xCurrent=0;
yCurrent=0;
zCurrent=0;
head=0;
tail=0;
xNew[0]=0;
yNew[0]=0;
zNew[0]=0;
feed[0]=Feed;
mCode[0]=-1;
steps=0;
sei();
}
}
}
}
}
Okay I worked It Out
I worked out where I was up to. I have not worked out how to "stack" the commands. I left the code with a simple one instruction at a time, issue and "ok" when done. So I need to add "stack" control code but otherwise it is ready for testing.
So it looks like a review of the serialEvent() subroutine, testing and add stack control code.
AlanX
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.