Having trouble with USB_VCP

Hey y’all,

I’m trying to get my openmv cam to output data directly into Blender through usb but I’m having some trouble actually getting information out. I have looked over the USB_VCP example in the IDE but still can’t seem to get anything readable out the other side. Right now I’m just trying to get the LED’s to light up when the cam is connected(I modified the LED example from the IDE). If I can get that done then I think I can figure out the rest on my own. When I open the serial port in Blender nothing lights up. Here is the code on the openmv cam. Any ideas what I’m doing wrong?

Side note: I was able to read data from an Arduino in Blender which makes me think I’m doing something wrong on the camera side.

import time, pyb
from pyb import LED

red_led   = LED(1)
green_led = LED(2)
blue_led  = LED(3)
ir_led    = LED(4)
usb = pyb.USB_VCP()


def led_control(x):
    if   (x&1)==0: red_led.off()
    elif (x&1)==1: red_led.on()
    if   (x&2)==0: green_led.off()
    elif (x&2)==2: green_led.on()
    if   (x&4)==0: blue_led.off()
    elif (x&4)==4: blue_led.on()
    if   (x&8)==0: ir_led.off()
    elif (x&8)==8: ir_led.on()

while(True):
    if (usb.isconnected()):
       for i in range(16):
            led_control(i)
            time.sleep(500)

Hi, you need to set DTR when the serial port is opened. See this example:

https://github.com/openmv/openmv/blob/master/scripts/examples/02-Board-Control/usb_vcp.py

I’ve tried using that code but it doesn’t seem to work. I’m not well versed in programming but my Blender version uses python 3.5.3 which I’m guessing is why that code isn’t working.

How do you run the code on openmv ? It must be saved as main.py and you can’t use the IDE and open the port at the same time.

That solved some of my problems. I thought I saved it correctly the first time but I guess I didn’t. I’ve gotten that example code working to some extent. I can now make a connection to the camera but I still can’t get the camera to relay ANY information. I keep getting a struct.error that says “unpack requires a bytes object of length 4”. This code is also for sending images when I really just want to send numbers, the FPS for example. Thank you for the quick replies, I’m sorry I don’t know more about this stuff.

Actually the code sends the image size first (a number) followed by a compressed image. You can modify the script to send numbers only. Just make sure the IDE is Not connected.

I keep getting the struct.error that says “unpack requires a bytes object of length 4” no matter what I send, I even tried changing the format character. When I take the ustruct.pack line out and just try to send the data nothing gets sent. Here’s what I’m using to try and just get a signal back into Blender, I can control the camera from Blender (turn LED’s on and stuff) I just can’t receive any data FROM the board. What am I doing wrong?!?!? I feel like I’m so close!
OpenMV code

import sensor, image, time, ustruct
from pyb import USB_VCP

usb = USB_VCP()
sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)
sensor.skip_frames(time = 2000)     # Wait for settings take effect.

while(True):
    cmd = usb.recv(4, timeout=5000)
    if (cmd == b'snap'):
        img = cmd
        usb.send(ustruct.pack("<L", img.size()))
        usb.send(img)

Blender code

import sys, serial, struct
port = 'COM2'
sp = serial.Serial(port, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, xonxoff=False, rtscts=False, stopbits=serial.STOPBITS_ONE, timeout=5, dsrdtr=True)
sp.write(str.encode("snap"))
sp.flush()
size = struct.unpack('<L', sp.read(4))[0]
img = sp.read(size)
sp.close()
print(img)

BTW this code gives me the struct.error from before.

Hi, your OpenMV Cam code is sending a stale image object.

import sensor, image, time, ustruct
from pyb import USB_VCP

usb = USB_VCP()
sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)
sensor.skip_frames(time = 2000)     # Wait for settings take effect.

while(True):
    cmd = usb.recv(4, timeout=5000)
    if (cmd == b'snap'):
        img = sensor.snapshot()
        usb.send(ustruct.pack("<L", img.size()))
        usb.send(img)

The above is what you want right? Because before the code would have just crashed on the camera. On the PC read(4) likely returned nothing because the camera code was wrong.

I’m actually not trying to send an image at all. Ideally I’d like to send the FPS of the camera and in the future the (x,y) coordinates of a blob. Just trying to wrap my head around this communication issue right now.

import sensor, image, time, ustruct
from pyb import USB_VCP

usb = USB_VCP()
sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)
sensor.skip_frames(time = 2000)     # Wait for settings take effect.

while(True):
    cmd = usb.recv(4, timeout=5000)
    if (cmd == b'snap'):
        img = sensor.snapshot()
        blobs = img.find_blobs([(0, 100, -127, 128, -127, 128)])
        if blobs:
            b = max(blobs, key = lambda x: x.pixels())
            usb.send(ustruct.pack("<L", len(str(b))))
            usb.send(str(b))

This would send the str representation of a blob.

I’m still getting the same struct.error in Blender.

“unpack requires a bytes object of length 4”

Whatever is being received is apparently not the correct length, if anything is being sent at all. What is the point of the ustruct.pack/struct.unpack lines? Do I need them? Why can’t I just usb.send(b)?
Thanks for all the help.

Hi, please verify the camera is sending something. The error is likely because the camera script is stopping because of an exception.

You can verify if everything is okay by using print instead of the USB vcp calls and then switch the USB vcp calls in once you know there are no other bugs.

When I use print() to show my values it works fine but sending data using USB_VCP isn’t working. I can RECEIVE data but the camera isn’t sending any info. In Blender I printed the length(len()) of the serial read and it came back as 0. Is there a timing issue?

Hmmm, all I can think of is the camera fauling for the vcp not being connected. Can you make the program not send until vcp.isconnected() returns true? class USB_VCP – USB virtual comm port — MicroPython 1.19.1 documentation

I’ll ask Ibrahim is he knows too.

When I run the code in the OpenMV IDE usb.isconnected() comes back True however when I run things from Blender usb.isconnected() comes back false. Made a simple LED test script to troubleshoot. When I check if the port is open through Blender it says it is but the LED’s on the board that are supposed to light up when usb.isconnected() == True are not lit up. The board is still receiving the “snap” message from the example code it’s just not recognizing itself as being connected I guess?

Here’s my LED troubleshooting script. When I run it in the IDE I just comment out the “if (cmd == b’snap’)” line. Thanks again for all the help.

import sensor, image, time, ustruct
from pyb import USB_VCP
from pyb import LED

usb = USB_VCP()
red_led   = LED(1)
green_led = LED(2)
blue_led  = LED(3)
sensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)
sensor.skip_frames(time = 2000)     # Wait for settings take effect.

while(True):
    if (usb.isconnected() == True):
        blue_led.on()
        red_led.off()
        green_led.off()
        time.sleep(200)
        blue_led.off()
        red_led.off()
        green_led.off()
        time.sleep(2000)
    cmd = usb.recv(4, timeout=5000)
    if (usb.isconnected() == True):
        blue_led.off()
        red_led.off()
        green_led.on()
        time.sleep(200)
        blue_led.off()
        red_led.off()
        green_led.off()
        time.sleep(2000)
        blue_led.on()
        red_led.off()
        green_led.off()
        time.sleep(200)
        blue_led.off()
        red_led.off()
        green_led.off()
        time.sleep(2000)
    if (cmd == b'snap'):
        red_led.off()
        green_led.on()
        blue_led.off()
        time.sleep(200)
        blue_led.off()
        red_led.off()
        green_led.off()
        time.sleep(2000)
        if (usb.isconnected()):
            blue_led.on()
            red_led.off()
            green_led.off()
            time.sleep(200)
            blue_led.off()
            red_led.off()
            green_led.off()
            time.sleep(2000)
        else:
            blue_led.off()
            green_led.off()
            red_led.on()
            time.sleep(200)
            blue_led.off()
            red_led.off()
            green_led.off()
            time.sleep(2000)

How do you open the serial port from blender ?

I just use the code from the USB_VCP example.

import sys, serial, struct
port = 'COM2'
sp = serial.Serial(port, baudrate=115200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, xonxoff=False, rtscts=False, stopbits=serial.STOPBITS_ONE, timeout=5, dsrdtr=True)
sp.write(str.encode("snap"))
sp.flush()
size = struct.unpack('<L', sp.read(4))[0]
data = sp.read(size)
sp.close()
print(data)

Your code is different, timeout=5 I think timeout is in milliseconds. I tested the following example on Linux and it’s working, can you try it ?

This is saved as main.py:

import ustruct
from pyb import USB_VCP

usb = USB_VCP()

while(True):
    try:
        cmd = usb.recv(4, timeout=5000)
        if (cmd == b'snap'):
            usb.send(ustruct.pack("<L", 1234))
    except:
        pass

And this is run from blender:

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.write(b"snap")
size = struct.unpack('<L', sp.read(4))[0]
sp.close()
print(size)

It prints (1234):

blender --background --python test.py 
1234
Blender quit

Note for isconnected to return True DTR must be set high. I see you’re testing on Windows maybe this is the issue. Anyway, let’s first try this simple example.

I tried your code and without a timeout Blender crashes. Once given a timeout though the script ran but I still was not receiving any data from the camera/still getting the struct error. The camera is still not recognizing it’s connected to send data but it still receives the “snap” message. I can try and get a Linux system up and going but I really don’t have the time. Also I think in Pyserial (the module for accessing the serial port in python) timeout is set in seconds.

The last script I sent doesn’t use isconnected() at all and it doesn’t wait for the camera to be connected (it waits until “snap” is received). Please test the code exactly as it is without any changes (well except for the timeout if that crashes blender).