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

Status
Not open for further replies.

educa

Active member
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 ?
 
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...
 
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 :(
 
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.
 
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.
 
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) ;)
 
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.
 
Status
Not open for further replies.
Back
Top