1. ## Proposed GX Protocol

This is a continuation of the protocol discussion that was started in the "New Stuff in the Chute" thread.

I also agree with RomanLini that for vector moves, the protocol should use a vector velocity, and not a single-axis velocity (otherwise, the velocity will have to be recomputed by the transmit end and prepended to each contouring move). However, this is almost what is described on page 6 of the geckomotion.pdf file that Mariss linked to in the other thread; so I think that we all are almost on the same page here. The major sticking point (if one can call it that) is that Mariss is proposing using the order of the axis callout as a selector for a register value to co-opt into a vector velocity; what I believe that RomanLini is (and I definitely am) suggesting that the vector velocity be explicitly called out as such and be only set once for any series of vector moves that have the same vector velocity. In other words, Mariss is suggesting "Vx1000x400y300" to get a vector move at a vector velocity of 1000 (but, if you do "Vx1000y300x400" you will not get the same result - the velocity used is not specified in that command; and will pick it up from whatever the last y axis velocity command was); what is being suggested by RomanLini and myself is something more like "V1000x400y300" (which will have the same effect as "V1000y300x400"). Not only is this approach simpler for the end user to understand, but it prevents certain kinds of bugs, and provides for a better packing efficiency in the protocol addition that I'm going to describe next. Oh, and IMHO, it's more elegant, too.

*************************************

I think that a binary protocol would be a good addition as well; and because ASCII only uses the lower 7 bits of a byte, it can co-exist with the ASCII protocol by defining all values with the high bit set (i.e, >=0x80) as binary values. To this end, I've whipped up some sample C code that encodes & decodes vector move commands; it's attached to the end of this post.

Basically, I've defined two closely related "binary-mode" vector move commands; the long form starts with a '!' character, and is followed by binary-packed values (the first byte being for which of the axes are in the command; and then axes themselves as 28 bit values packed into 4 bytes, for a machine with a resolution of 0.0001 inches this gives a positioning envelope of over .4 of a mile). The short form starts with a '*' character; and uses a 7-bit signed incremental value for the axis moves (it's intended for curve-contouring, where you have a whole bunch of very short moves in a row). For the long form, 2 axis moves without a velocity term take up 10 bytes; in the short form that same move (assuming it fits - short form moves are limited to +-63 steps per move) takes up 4 bytes.

I also noted that there seems to be no reset command; I would suggest that receiving an escape character (0x1B) should clear the receive buffer. Also, receiving any of the binary-mode command start characters ('!' or '*') should clear the receive buffer; and if any command is malformed an error notification should be sent to the host (allowing it to respond with a re-transmission, in long-form if required).

*************************************

The other thing to keep in mind when thinking about this is that this interface protocol is not intended to be a human-level interface; and perhaps not even a stored data format, but rather expanded-to on-the-fly by some processor that takes in some other format (i.e, G-Code, a CAM or artwork format, or perhaps even an interactive controller that takes direct-button-pushes-on-the-front-panel and generates curve moves) or generated in response to sensor input (i.e, adaptive robotics applications). This is why it doesn't have any curve interpolation capability, or logic functions, etc - all that is handled by external equipment.

*************************************

The binary packing code I mentioned above:

Code:
```/*
*  ContouringProtocol.h
*/

#include <sys/types.h>

typedef u_int8_t CPPacked7[1];
typedef u_int8_t CPPacked14[2];
typedef u_int8_t CPPacked28[4];

enum
{
};

enum
{
CPAxis_x=0,
CPAxis_y,
CPAxis_z,
CPAxis_a,
CPAxis_b,
CPAxis_c
};

typedef struct
{
u_int16_t targetVelocity;	// This is the target feed rate, as a velocity along the vector in steps per second
u_int8_t axisMask;			// This is a bit mask that specifies which of the values are valid.
int32_t axisPosition[6];	// axisPosition[0] is x, axisPosition[1] is y, etc...
} CPVectorCommand;

typedef struct
{
u_int8_t length;
u_int8_t bytes[28];
} CPPackedVectorCommandBuffer;

extern void PackCPVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command);
extern void UnpackCPVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command);
extern void PackCPShortVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command);
extern void UnpackCPShortVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command);```

Code:
```/*
*  ContouringProtocol.c
*/

#include "ContouringProtocol.h"

static inline void PackIntoCPPacked7(CPPacked7 buffer, u_int8_t value)
{
buffer[0]=value|0x80;
};

static inline void PackIntoCPPacked14(CPPacked14 buffer, u_int16_t value)
{
buffer[0]=((u_int8_t)value)|0x80;
buffer[1]=((u_int8_t)(value>>7))|0x80;
};

static inline void PackIntoCPPacked28(CPPacked28 buffer, u_int32_t value)
{
buffer[0]=((u_int8_t)value)|0x80;
buffer[1]=((u_int8_t)(value>>7))|0x80;
buffer[2]=((u_int8_t)(value>>14))|0x80;
buffer[3]=((u_int8_t)(value>>21))|0x80;
};

static inline u_int8_t UnpackFromCPPacked7(CPPacked7 value)
{
return value[0]&0x7F;
};

static inline int8_t UnpackFromCPPackedS7(CPPacked7 value)
{
int8_t result=value[0]&0x7F;
if(result&0x40) result|=0x80; // Performs the sign extension.
return result;
};

static inline u_int16_t UnpackFromCPPacked14(CPPacked14 value)
{
return	(value[0]&0x7F)|
(((u_int16_t)(value[1]&0x7F))<<7);
};

static inline u_int32_t UnpackFromCPPacked28(CPPacked28 value)
{
return	(value[0]&0x7F)|
(((u_int16_t)(value[1]&0x7F))<<7)|
(((u_int32_t)(value[2]&0x7F))<<14)|
(((u_int32_t)(value[3]&0x7F))<<28);
};

void PackCPVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command)
{
u_int8_t *cursor=buffer->bytes;
*cursor='!'; cursor++;
{
PackIntoCPPacked14(cursor,command->targetVelocity); cursor+=2; buffer->length+=2;
};

for(u_int8_t i=0; i<6; i++)
{
{
PackIntoCPPacked28(cursor,command->axisPosition[i]); cursor+=4; buffer->length+=4;
};
};
};

void UnpackCPVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command)
{
u_int8_t *cursor=buffer->bytes+1;
{
command->targetVelocity=UnpackFromCPPacked14(cursor); cursor+=2;
};

for(u_int8_t i=0; i<6; i++)
{
{
command->axisPosition[i]=UnpackFromCPPacked28(cursor);
cursor+=4;
};
};
};

void PackCPShortVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command)
{
u_int8_t *cursor=buffer->bytes;
*cursor='*'; cursor++;
{
PackIntoCPPacked14(cursor,command->targetVelocity); cursor+=2; buffer->length+=2;
};

for(u_int8_t i=0; i<6; i++)
{
{
PackIntoCPPacked7(cursor,command->axisPosition[i]); cursor++; buffer->length++;
};
};
};

// Note: This function assumes that command already contains the previous axis position values that will be updated with the diffrence values from buffer.
void UnpackCPShortVectorCommand(CPPackedVectorCommandBuffer *buffer, CPVectorCommand *command)
{
u_int8_t *cursor=buffer->bytes+1;
{
command->targetVelocity=UnpackFromCPPacked14(cursor); cursor+=2;
};

for(u_int8_t i=0; i<6; i++)
{
{
command->axisPosition[i]+=UnpackFromCPPackedS7(cursor);
cursor++;
};
};
};```

2. Hmm... NO opinions? Not even to tell me that I'm an idiot and can't program my way out of a wet paper bag?

3. Britt,

Sorry. I mean to get with you as soon as I finish writing the controller's interrupt service routine. There's a lot of stuff in it that has to execute real fast so it has to be written in assembly. It's mostly done; I've just have a couple of 32-bit integer math routines left to write.

Mariss

4. Sorry. I mean to get with you as soon as I finish writing the controller's interrupt service routine.
Mmm... that's OK. I know you're busy working on new geckos... (and I had guessed based on various bits of evidence that the forum leaves behind that you had read it)... I was just a little but surprised that nobody else had anything to say, in the week that the first post was up.

*************************************

Also, it occurs to me that a current position and command completed feed-back mechanism would be very useful. For current position, I would suggest a command that would turn on periodic reporting, and then just send back the contents of the current position registers (in either ASCII or long binary format, depending on which feedback mode you had turned on).

For command completed, I would suggest that if a prefix of a command number is prepended to the command (perhaps by sending a '#', followed by either a binary-packed command number, or an ASCII version of one), and that the motor controller would send back to the host the command number after each numbered command is completed (perhaps prefixed by the same '#' byte, and in the same format --- ASCII or binary-packed --- as was sent with the command).