Skip to main content

python interface

Michael's picture
Posted in

Hi church,
Great project! In the next weeks I might have some time to contribute some stuff. Is there a documentation about the serial protocol? Otherwise I will extract it from OM_Serial_Com_Client.pde. I don't like (or know) perl too much, so I want to write the communication in python...
Furthermore: I did not check the perl ui yet, but I wondered if there is a GUI. If not, then I could write one in QT.

Cheers,
Michael

Hey Michael! I haven't had a

Hey Michael!

I haven't had a chance to document the serial protocol yet, as it's the hardest part of the documentation *grin* The serial com pde file is probably the best location, as the comments at the beginning of the PDE detail every aspect of the serial protocol. However, as data is sent in a native format (e.g. two bytes represent a 16 bit number, rather than trying to express the data as a series of ascii character bytes), it will help to look at the perl code, as both perl and python use a pack() function. (Although in python it's struct.pack(), IIRC.) While you'd have to convert the perl templates to python templates, they would be highly instructive. Just look for pack() in a given function in the perl code.

A key point is that all data used is big-endian, don't use little-endian pack templates. =)

I haven't started on a GUI yet, and would love it if you did - that would be great!

!c

Great, everything runs

Michael's picture

Great, everything runs perfectly with your perl interface, the stepper is happily stepping and the camera clicking :-)
So now some questions to the protocol: So, byte 0 tells the arduino which subsystem you are talking to, e.g. the camera or the motor, then the second byte is the command to the corresponding subsystem.
So, e.g. "'1' '3'" means "stop the execution of the program"
or "'2' '2' '1' '0' '50'" means "Set the motor steps of motor 0 to 50"
So I have to pack these bytes as big-endians (god thanks :-) )?

What I wonder now is how does the arduino know how long a message is? Do you use a start byte (like e.g. %) and a end byte (e.g. $)?

Protocol and Data Length

Michael,

The first byte is actually a 'primary' command. There are two primary commands supported right now, 'program control' [1] and 'set program data' [2] (aka 'configure'). You can look at it this way: a program control command will result in something happening immediately, and a set program data will change some operating parameter of your current program in the engine. (e.g.: how far motor 1 should move between shots, what actions are available, which keyframes are set, how often to fire the camera, etc.)

The data length to be transmitted is the second byte, so the protocol supports up to 255 total data bytes for a given primary command, although I don't think we'd ever use that =). The important part about this one, is it is the length of bytes AFTER the first two. Never include the first two (primary command and data length bytes) in the data length value.

The third byte is the secondary command.

So, for example, to start the program running, I would send three bytes:

111 (as B00000001 B00000001 B00000001 - binary '1', unsigned char or byte value in arduino world)

Primary command: Program Control
Data Length: 1 byte
Secondary Command: Start

Now, you may ask "what do I do when there's data corruption and I don't complete my command?" The engine will wait until it receives all of the bytes you told it you'd send. I had originally built in a time-out function into the serial code, but that took another 64 bytes of memory for the counter alone, and I thought that un-frugal when pretty much all serial interfaces could report the actual number of bytes transported when writing to a serial port. So, what you would do is finish off your remainder of control bytes with 0x0 (binary 0) until you've accomplished the bytes you said you would send, and then re-submit your intended command, making sure you had transmitted enough bytes. Generally, this is safe.

I intend to add response data to the protocol in the not-so-distant future, so you can know whether your command was accepted or not.

So, yeah, as to pack templates - just remember that when it says it wants two bytes for a value, that you pick a template that produces an _unsigned big-endian value of exactly two bytes_ that would be 'n' in the perl pack templates. e.g., in perl I would say :

$data .= pack('n', $value);

A more complete example: (set motor 0 to 50 steps):

$command  = pack('C', 2); # program data
$sub_com  = pack('C', 2); # motor control sub-command
$sub_com .= pack('CC', 1, 0); # set motor steps, motor #
$sub_com .= pack('n', 50); # store step count as 16 bit unsigned big-endian value

$command .= pack('C', length($sub_com) ); # add data len byte to command
$command .= $sub_com; # add rest of data to primary command and data len

!c

cool, it works!!

Michael's picture

cool, after reading your stuff I was able to stop the motor by sending "pause" with python, yeah!

command = struct.pack("c","\1")
command += struct.pack("c","\1")
command += struct.pack("c","\2")
ser = serial.Serial("COM3",19200)
ser.write(command)

Maybe a "state" function would be great, such that the arduino sends all the parameters set by the user?

cool, it works!!

Dan's picture

Nice one Michael! So is the commmand above just for pause? It would be great to have document like a table somewhere for all of the relevent python commands. I've been trying to learn perl but would feel much more confortable in python. Also are you using the pyserial module for this?

Dan.

Hi Dan, yes, I use pyserial!

Michael's picture

Hi Dan, yes, I use pyserial! I also prefer python over perl...
I will try to write the same dictionary for the arduino commands church uses in his perl code in python. From there it is straight forward to implement the interface functions!