Reading stream of data sent from OpenMV to Raspberry Pi through USB

Hi all,

I have been trying to send a stream of data from the OpenMV which I am using for image processing and then output numbers to my Pi in order to guide a robot I am building for a project.

I am able to receive the data and read it when using the screen function on the Pi, however I seem to only be receiving unusable values when I try to read it with my python script.
I am unsure if this is a problem with how the data is being sent from the camera or if it is a problem with how the Pi is reading it.

I am using an OpenMV M7 and a Raspberry Pi 3 B+ running Ubuntu Mate.
The OpenMV code is some linear regression code from the OpenMV blog that I have made some minor changes to.

Code for the OpenMV camera:

BINARY_VIEW = True
GRAYSCALE_THRESHOLD = (0, 230) #230
MAG_THRESHOLD = 4
THETA_GAIN = 40.0
RHO_GAIN = -1.0
P_GAIN = 0.7
I_GAIN = 0.0
I_MIN = -0.0
I_MAX = 0.0
D_GAIN = 0.1


import sensor, image, time, math, pyb

usb = pyb.USB_VCP()

sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)
#sensor.set_vflip(True)
#sensor.set_hmirror(True)
sensor.skip_frames(time = 2000)
clock = time.clock()

def line_to_theta_and_rho(line):
    if line.rho() < 0:
        if line.theta() < 90:
            return (math.sin(math.radians(line.theta())),
                math.cos(math.radians(line.theta() + 180)) * -line.rho())
        else:
            return (math.sin(math.radians(line.theta() - 180)),
                math.cos(math.radians(line.theta() + 180)) * -line.rho())
    else:
        if line.theta() < 90:
            if line.theta() < 45:
                return (math.sin(math.radians(180 - line.theta())),
                    math.cos(math.radians(line.theta())) * line.rho())
            else:
                return (math.sin(math.radians(line.theta() - 180)),
                    math.cos(math.radians(line.theta())) * line.rho())
        else:
            return (math.sin(math.radians(180 - line.theta())),
                math.cos(math.radians(line.theta())) * line.rho())

def line_to_theta_and_rho_error(line, img):
    t, r = line_to_theta_and_rho(line)
    return (t, r - (img.width() // 2))

old_result = 0
old_time = pyb.millis()
i_output = 0
output = 90
operation = ""

while True:
    out_tot = 0
    out_avg = 0
    for x in range(3):
        clock.tick()
        img = sensor.snapshot().histeq()
        if BINARY_VIEW:
            img.binary([GRAYSCALE_THRESHOLD])
            img.erode(1)

        line = img.get_regression([(0, 0)], robust=True)
        print_string = ""

        if line and (line.magnitude() >= MAG_THRESHOLD):
            img.draw_line(line.line(), color=127)

            t, r = line_to_theta_and_rho_error(line, img)
            new_result = (t * THETA_GAIN) + (r * RHO_GAIN)
            delta_result = new_result - old_result
            old_result = new_result

            new_time = pyb.millis()
            delta_time = new_time - old_time
            old_time = new_time

            p_output = new_result
            i_output = max(min(i_output + new_result, I_MAX), I_MIN)
            d_output = (delta_result * 1000) / delta_time
            pid_output = (P_GAIN * p_output) + (I_GAIN * i_output) + (D_GAIN * d_output)

            output = 90 + max(min(int(pid_output), 90), -90)
            print_string = "Line Ok - turn %d - line t: %d, r: %d" % (output, line.theta(), line.rho())
        else:
            print_string = "Line Lost - turn %d" % output
        out_tot += output

    out_avg = out_tot // 3
    
    usb.send(str(out_avg), timeout=100)

Code for the Raspberry Pi:

#!/usr/bin/python
import serial
ser = serial.Serial()
ser.port = "/dev/ttyACM0"
ser.baudrate = 115200
ser.timeout = 100
ser.open()
while True:
	if ser.isOpen():
		value = ser.read()
		print(value)

Hi, you’re the second person who’s mentioned the VCP port might be unstable. What errors are you getting exactly?

You didn’t quite mention what the problem is in detail.

I tested your code, seems to be working. Try opening the port like this:

import sys, serial, struct
port = '/dev/ttyACM0'
sp = serial.Serial(port, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE,
            xonxoff=False, rtscts=False, stopbits=serial.STOPBITS_ONE, timeout=None, dsrdtr=True)
sp.setDTR(True) # dsrdtr is ignored on Windows.
print(sp.read())

I tried iabdalkader’s code and I am getting the same problem as before.

The problem I am having is what I am reading with the python code. I am trying to send the output value through USB which is a value such as 90 or 104, and when I use screen /dev/ttyACM0 115200 I am able to see the numbers being sent. However when I try to read it using python code I am receiving values like b’7’ and b’1’. And these values do not seem to be consistent. When I am looking at the bit stream with screen, I can see the same value repeating like 90909090909090 if I am not moving the camera indicating that nothing is changing as expected. However when reading with the python code, the values are changing constantly and seem to have no pattern.

This is not a problem with the port it’s how you send the data, you send a str and when you recv you read 1 byte at a time, I get the same values. If you want to send a 4 bytes int and read that try:

usb.send(ustruct.pack("<L", 90))

Then read 4 bytes and unpack:

struct.unpack('<L', sp.read(4))[0]

That was my problem.
Thank you for your help.