4

I have been working on a project using Python to read values from an arduino and then control video cameras. The Arduino controls two ultrasonic sensors and reports distance in cm. The python script then reads the distances from the Arduino using ser.readline(). When the script reads values outside the range everything works fine. However if it goes into the loop for the distance inside the required range it works correctly once and then reads old values from the Arduino instead of current "live" values which causes it to continue the record loop instead of exiting the loop. What can I do to get rid of the old values in the buffer and only read the most current value? I have found several methods and tested them but so far no luck.

Here is the code I am using (i know its not well written but its my first try using python and writing code outside of matlab)

import sys, time
import serial
import cv
import os
from time import strftime

#Create window for Camera 0
cv.NamedWindow("Camera 0", cv.CV_WINDOW_AUTOSIZE)
capture0 = cv.CreateCameraCapture(2)
cv.ResizeWindow("Camera 1", 640, 480)
cv.MoveWindow("Camera 0", 0, 0)
#Create window for Camera 1
cv.NamedWindow("Camera 1", cv.CV_WINDOW_AUTOSIZE)
capture1 = cv.CreateCameraCapture(1)
cv.MoveWindow("Camera 1", 150, 150)

#Initialize connection to Arduino
arduino = serial.Serial('COM12', 9600)

connected = False

#Confirm that Arduino is connected and software is able to read inputs
while not connected:
    serin = arduino.readline()
    connected = True
    f = 'Sensor Connected'
    print f

'''#Dummy variables for testing
value1 = 145
value2 = 30'''

#Initialize video record on as false (0)
vid = 0

#Initialize counter
counter_vid = 0
counter = 0

Accel = 1

def Camera0():
    frame0=cv.QueryFrame(capture0)
    cv.WriteFrame(writer0,frame0)
    cv.ShowImage("Camera 0", frame0)

def Camera1():
    frame1=cv.QueryFrame(capture1)
    cv.WriteFrame(writer1,frame1)
    cv.ShowImage("Camera 1", frame1)

while True:
    status = arduino.readline()
    value1=int((status[6:10]))-1000
    value2=int((status[17:21]))-1000
    print(value1)
    print(value2)
    if value1>180 and value2>180 and vid==0:
        vid = 0
    elif value1>180 and value2>180 and vid==1:
        vid = 0
    elif value1<180 and vid==0 or value2<180 and vid==0:
        filename0 = strftime("OUTPUT\%Y_%m_%d %H_%M_%S") + " camera0.avi"
        writer0=cv.CreateVideoWriter(filename0, 1, 15.0, (640,480), is_color=1)
        filename1 = strftime("OUTPUT\%Y_%m_%d %H_%M_%S") + " camera1.avi"
        writer1=cv.CreateVideoWriter(filename1, 1, 15.0, (640,480), is_color=1)
        vid=1
        while counter_vid<25 and vid==1:
            Camera0()
            Camera1()
            counter_vid += 1
            print(counter_vid)
            cv.WaitKey(10)
    else:
        while counter_vid<25 and vid==1:
            Camera0()
            Camera1()
            counter_vid += 1
            print(counter_vid)
            cv.WaitKey(10)        

    cv.WaitKey(25)
    counter_vid = 0
    counter += 1
    print('End of Loop Counter')
    print(counter)
dsolimano
  • 8,870
  • 3
  • 48
  • 63
  • About 88% of that code looks irrelevant to problem -- I suggest you try some code that leaves out all the camera stuff and perhaps does a dozen reads separated by brief delays and revise question with that brief code and its results – James Waldby - jwpat7 Dec 01 '12 at 21:22
  • When I do that it actually works fine. Its just when everything gets added together that I have issues. Thats why I think its a buffer problem, in the time it takes to process everything values are being stored in the arduino buffer and the next iteration i get the next value in the buffer but in reality that value happen x amount of time ago and I actually what the most current value not the first in buffer. – user1869324 Dec 02 '12 at 17:12
  • To see if camera-processing-delay is related to the problem, try the non-camera code with different delays in place of the camera code. Eg `import time; dt=0.05` (or `dt=0.25` etc) and then put `time.sleep(dt)` statements in place of camera code. – James Waldby - jwpat7 Dec 02 '12 at 17:51
  • possible duplicate of [pyserial - How to read the last line sent from a serial device](http://stackoverflow.com/questions/1093598/pyserial-how-to-read-the-last-line-sent-from-a-serial-device) – Seanny123 Mar 14 '15 at 15:51

1 Answers1

2

You're right about the buffer filling up. You need a way to always get the most recent value out of the buffer.

I would suggest replacing this:

status = arduino.readline()

with this:

status = getLatestStatus()

and then further up towards the top, by your camera functions:

def getLatestStatus():
    while arduino.inWaiting() > 0:
        status = arduino.readline()
    return status

This function getLatestStatus will go through the entire buffer every time it is called and only return the latest status, disregarding all the statuses returned in the meantime.

Your other option is to modify the "firmware" for your arduino to return a distance sensor value every time it receives a command, (say "M\n") so that way you don't have to worry about buffer problems. That's what I did for an arduino-powered ultrasonic distance device and I felt it was cleaner than the "read through the entire buffer" solution. It will introduce a bit more latency into your distance measurement though.

Mike Sandford
  • 1,315
  • 10
  • 22