0
\$\begingroup\$

okay so my situation is that i am working an avr chip which is the atmega 328p and what i want to do is i want to lets say have a user input in python lets say the user types in a string and from there i want my avr c code to interpret the code.

The reason i am doing this is because i am making a basic cnc gui so the user will input a stepper motor axis like x y or z then the direction "-" or "+".

Then a distance which is a number into python and then from python i want to send this info to the avr-c code which will then use the info to control steppers.

I want to avoid using the default serial communication thing in avr c because it will be harder to do since the user will input strings like "x-20 y+10" and etc.

It is much easier to use python to interpret the text then to use avr-c so how would i go about doing this ////////AFTER SOMETIME//////////////////////////
okay so after much confusion and researching I came up with a code based on the syntax of pyserial as well as the struct modules, here is the code:

            import serial
            import struct 
            import binascii 

            #Function to Initialize the Serial Port
            def init_serial():

                global ser       #Must be declared in Each Function
                ser = serial.Serial()
                ser.baudrate = 9600

                ser.port = '/dev/ttyACM0' #com port of avr 

                ser.timeout = 10
                ser.open()          #Opens SerialPort
                # print port open or closed
                if ser.isOpen():
                    print 'Open: ' + ser.portstr

                    init_serial() 
                    values = (1)
                    s = struct.Struct('I')  
                    packed_data = s.pack(*values)

            ser.write(packed_data)    #Writes to the SerialPort

            while 1:    

                bytes = ser.readline()  #Read from Serial Port
                packed_data = binascii.unhexlify(bytes)
                s = struct.Struct('I') 
                unpacked_data = s.unpack(packed_data)
                print 'You sent: ', unpacked_data      #Print What is Read from Port

            #Ctrl+C to Close Python Window

Please inform me if I am doing something wrong or right, or if this code work actually work at all, if so this is the python side of the transmission of python data to avr-c, how would I then handle the avr-c side of this communication with python over serial communication?

\$\endgroup\$
  • \$\begingroup\$ Where will the python program be located, on a PC? You basically want to send data from PC to AVR ? \$\endgroup\$ – Golaž May 3 '15 at 13:12
  • 5
    \$\begingroup\$ okay so your text is kinda hard to read with the lack of capitals and punctuation while you are at it you might want to consider an authoring style that resembles written language a bit more than spoken language \$\endgroup\$ – jippie May 3 '15 at 16:30
  • \$\begingroup\$ yes i am planning to have a python program on my computer and i am going to send them to avr so basically from pc to avr \$\endgroup\$ – Redrachet2 May 3 '15 at 19:21
  • \$\begingroup\$ and also sorry for the sloppy format oli had to quickly type this on my mobile hopefully the new edits will make it easier to read \$\endgroup\$ – Redrachet2 May 3 '15 at 19:27
  • \$\begingroup\$ Serial communication is very easy. On the other hand, if you are working with CNC, then you should implement G-code. Don't reinvent the wheel.. \$\endgroup\$ – Ashton H. May 3 '15 at 19:35
5
\$\begingroup\$

One option is to parse the string in python and then send some sort of binary format to the microcontroller. This would be more efficient bandwidth-wise and the MCU code will be much simpler. The link to the microcontroller would still be serial, but you would not be limited to sending printable characters. It's quite easy to do open a serial port with pyserial in binary mode and then do port.write(struct.pack(....)) to send binary data down the link.

In your C code, you can declare a structure and then cast a pointer to the received data to a pointer to the structure and then directly read out the data elements, no parsing required.

I actually have a bunch of packet processing code that I wrote a few years ago for an AVR project here: https://github.com/alexforencich/xgrid/blob/master/firmware/xmega/xgrid.cpp. It's not designed to be used with the Arduino environment, but it should be able to run on the 328. There is a bunch of other stuff in there that's specific to this particular project, but take a look at send_raw_packet, try_read_packet, and try_parse_packet to get a feel for how you can transfer structured binary data over the serial port.

Update:

Looks like you're looking at the right libraries for sending data to the AVR, but there are still a few things that you should look at. First, the idea behind binary protocols is to send blocks of binary data which are defined by structs. For example, you might need to send a point object that has an X and a Y coordinate. You would define this in C as

struct point {
    int16_t x;
    int16_t y;
};

In C, you can create an instance of the struct, initialize it with the required data, create a pointer to it, and cast it to a char pointer, and send it to the serial port:

struct point p;
p.x = 1;
p.y = 2;
uart.write((char *)&p, sizeof(point));

Then in python, you would do something like

(x, y) = struct.unpack("hh", ser.read(4))

To go the other way, you can invert the whole process like so:

ser.write(struct.pack("hh", x, y))

And then on your microcontroller:

struct point p;
usart.read((char *)&p, sizeof(point));
x = p.x;
y = p.y;

Now, you will need to do more work than just this to support things like framing and object identification (some sort of packet type field), but this should be enough to get you started.

I said it before and I will say it again: look at the implementation of try_read_packet here: https://github.com/alexforencich/xgrid/blob/master/firmware/xmega/xgrid.cpp#L257 . This manages atomically pulling packets out of the UART receive queue in a nonblocking fashion - it will do nothing and return 0 if the whole packet is not in the buffer, otherwise it will read out the packet and parse it. The packets themselves are built from a fixed identifier byte 0x5A followed by a 2 byte length followed by the payload data. Well, sortof. The packets used in that project actually have a bunch of other standard fields, but those first 3 bytes are handled differently in try_read_packet as it has to read them to know how big the packet is, and the rest is handled as payload data. The implementation of try_read_packet is quite simple. It drops characters until it sees 0x5A. Then it uses peek to get the length without dequeueing the bytes. If the whole packet is available, it reads it into a buffer and passes it to try_parse_packet, which casts the buffer pointer to a structure pointer and reads out the header fields. The idea is you can call this routine in a loop and process packets as they arrive. The transmit side is dirt simple, just set all the correct fields in the struct, get a char pointer to it, and pass that off to the UART module for transmission.

\$\endgroup\$
  • \$\begingroup\$ Thank you so much for the guidance and resources, my plan is to make python take care of all the string stuff then send the corresponding number equivalents to axis direction and step variables in my c-code, and again thank you very much \$\endgroup\$ – Redrachet2 May 4 '15 at 2:09
  • \$\begingroup\$ I am having trouble with understanding how to write python and send the data from the python program to the avr-c to accept, one of my friends told me to research bit manipulation in python as well byte string short integer in python, other than that does any one know any good tutorials on this subject matter \$\endgroup\$ – Redrachet2 May 6 '15 at 0:05
  • 1
    \$\begingroup\$ Look at the docs for python struct. Bit manipulation is important too, but it's basically the same as C. struct will do all of the packing and unpacking for integers. \$\endgroup\$ – alex.forencich May 6 '15 at 7:08
  • \$\begingroup\$ So I ready every thing in the struct module and I did read about bit manipulation, but if I were to use the struct module then would I still need the bit manipulation, could I just rely on the module to do everything for me \$\endgroup\$ – Redrachet2 May 6 '15 at 16:45
  • \$\begingroup\$ struct works on bytes only, so yes, you may need to do bit manipulation as well. Basically, if you want to send a 32 bit flag field, you would have to set the bits you want in an integer, pack that into 4 bytes with the struct module, and send it over the serial link. \$\endgroup\$ – alex.forencich May 6 '15 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.