Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

Thread: Problem synchronising Python serial with teensy 3.6 (works once after reprogramming)

  1. #1
    Member educa's Avatar
    Join Date
    Jan 2017
    Location
    Belgium
    Posts
    21

    Problem synchronising Python serial with teensy 3.6 (works once after reprogramming)

    Hi,

    I am trying to make a very simple program in python which sends binary data to a teensy 3.6 in chunks of 5 bytes.

    I wrote the following program for this in python

    Code:
    from PIL import Image
    import serial
    
    
    ser = serial.Serial('/dev/cu.usbmodem2641171', 9600)
    chip_img = Image.open('bart.png');
    size = width, height = chip_img.size;
    chip_img = chip_img.convert('1')
    for yy in range(0,height):
        for xx in range(0,width):
            coordinate = x, y = xx, yy
            waarde= chip_img.getpixel( coordinate )
            if waarde == 0:
                print "pixel",xx,",",yy," must burn" 
                outByte1= (xx>>8) & 0xff
                outByte2= xx & 0xff
                outByte3= (yy>>8) & 0xff
                outByte4= yy & 0xff
                ser.write(chr(outByte1))
                ser.write(chr(outByte2))
                ser.write(chr(outByte3))
                ser.write(chr(outByte4))
                ser.write(chr(7))
    ser.close()
    Now this code just opens an image (bart.png) , converts it to black and white and for each black pixel in the image it sends 5 bytes.
    byte 1 + 2 are the 2 bytes making the X coordinate of the pixel
    byte 3 + 4 are the 2 bytes making the Y coordinate of the pixel
    the fifth byte is by default always the number 7 (for the time being, since this will also become a variable value later on)

    The code does this for each black pixel and then stops.


    This is the teensy side of code

    Code:
    void setup() {
      // put your setup code here, to run once:
      analogWriteResolution(12);
      analogWrite(A22,2048); //center DAC1
      analogWrite(A21,2048); //center DAC0
      analogWrite(A9,10); //set a very low pwm duty on pin A9
      Serial.begin(9600);
    }
    
    
    void loop() {
    if (Serial.available()>=5) 
        {
        byte inByte1 = Serial.read();
        byte inByte2 = Serial.read();
        byte inByte3 = Serial.read();
        byte inByte4 = Serial.read();
        byte inByte5 = Serial.read();
        analogWrite(A22,4*(256*inByte1+inByte2));
        analogWrite(A21,8*(256*inByte3+inByte4));
        delay(50);
        analogWrite(A9,4096);
        delay(inByte5);
        analogWrite(A9,10);
        }
    }
    So the teensy first sets the dacs to 12 bit resolution and centers them both to value 2048 + it sets A9 to a very very low duty cycle PWM

    In the loop I wait until there are 5 or more bytes available on serial, then read these 5 bytes and do some setting with these values.
    The loop continuously checks for bytes in serial



    This works very nicely. I upload the code to teensy, I start the python script and everything works fine THE FIRST TIME.

    If the python program ends and I let the teensy run without altering anything, then when I restart the python program, the system doesn't seem to be synchronised anymore. It is like opening the connection throws in some garbage or whatever, but the values of outByte1, outByte2, ets .... are not received by their corresponding inByte1, inByte2, ....

    Instead it looks like the inbyte1 receives data which was send by outByte2,3,4,5.... but that means the data is useless for further processing.



    Is there something I can do to make 100% sure at the beginning of my python script that my data is synced ?

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,910
    I am guessing the main issue is that when the python script is running and then you startup the teensy, all it sees are some random bytes, there is no way for it to know where the begging of the image data is.

    One way to potentially do this, is to have the python script output a fixed header, example 0xff 0xff 0xff 0xff 0xff at the start of the image. This assumes that image position of x and y of 65535 is not valid.

    Then have your teensy code start up looking for these 5 0xff values before starting up your main loop...

  3. #3
    Member educa's Avatar
    Join Date
    Jan 2017
    Location
    Belgium
    Posts
    21
    The teensy does work perfect the first time the program runs after I uploaded the code. then when I restart the python script it gets out of sync

    so it always works perfect first time but not second or third time. In fact sometimes it works, sometimes it does not

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    4,910
    As I mentioned, you need some way to get the two boards in sync and maybe do some data validation.

    For example if the teensy reads in an extra byte or two at the end it will just hold onto them when it starts your next run of the script...

    So I would tend to add additional handshake like I mentioned.

    Like the header I mentioned at the start.

    Like, maybe not necessarily wait for 5 bytes to process, and do simple test like if I receive 2 bytes and then no bytes for some specific timeout time, then toss the two bytes.

    Like maybe add 6th byte which is checksum of the first 5 and verify that.

    Like check do the y's and x's look valid, the y's should be incrementing and for like y's the X's should also increment.

    Again lots of options.

  5. #5
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    If you can tolerate some overhead, sending ASCII data is a good option. You could send 1 line per pixel, the line feed is your synchronization marker.

    If 7 bits per byte are good enough, you could use 1 bit as packet start marker (only the first byte in a packet will have the marker bit set).

    Otherwise, look at SLIP or COBS, which are intended for packetizing streams. There are a lot of libraries, both for Teensy/Arduino and Python.

  6. #6
    Member educa's Avatar
    Join Date
    Jan 2017
    Location
    Belgium
    Posts
    21
    I'll do some testing with these things.

    I did find out that when I RESET the teensy 3.6 (reset pin on bottom pad connected to gnd for a fraction of a second) then the python script works every time, so that could be a solution too since each time I want to use this code I do have to do some specific manual job, so pressing a reset button could be a way to go (unless I figure out some handshaking of course)

  7. #7
    Senior Member
    Join Date
    Apr 2013
    Posts
    1,879
    You really want some form of error correction/handshake. A simple hack it to have a counter/timer that runs between bytes. If more than X milliseconds passes before another set of bytes shows up trigger an abort (especially if this is for the laser mentioned in your other post) and reset all the state counters to zero, and possibly also send a message back to the PC to say it's failed and ready to resend.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •