Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2C NXTCam-v5 Python program #1007

ec-m opened this issue Nov 15, 2017 · 5 comments


None yet
2 participants
Copy link

commented Nov 15, 2017

I would like to communicate with my NXTCam-v5 via I2C to receive the coordinates of multiple objects. I am using ev3dev with Python and I am wondering whether someone has implemented I2C communication between the EV3 and the NXTCam-v5 (or any similar sensor) in Python and could provide some code? That would be great - thank you.

Image file: ev3dev-jessie-ev3-generic-2017-09-14
Kernel version: 4.4.87-22-ev3dev-ev3
Board: LEGO MINDSTORMS EV3 Programmable Brick
Revision: 0006
Brickman: 0.8.1
ev3devKit: 0.4.3


This comment has been minimized.

Copy link

commented Nov 15, 2017

This is NOT ev3dev-lang-python, but here is something I was playing around with...

#!/usr/bin/env micropython
"""Sample program using EXPLOR3R"""

from uev3dev import *

# init display
display = Display()
fbuf, fbuf_data = display.framebuffer()

# init motors
left_motor = LargeMotor('B')
right_motor = LargeMotor('C')

# fun with I2C

in4 = EV3InputPort('4')
in4.mode = 'other-i2c'
bus4 = SMBus('/dev/i2c-in4')

firmware = bytes(bus4.read_i2c_block_data(0x00, 8)).decode().strip()
vendor = bytes(bus4.read_i2c_block_data(0x08, 8)).decode().strip()
product = bytes(bus4.read_i2c_block_data(0x10, 8)).decode().strip()
debug_print(firmware, vendor, product)

if vendor != 'mndsnsrs' or product != 'NXTcam5':
    raise ValueError('Wrong sensor')

# functions

def scale(x1, y1, x2, y2):
    """Convert points from NXTCam to screen rectangle"""
    x1 = x1 * display.width // 240
    y1 = y1 * display.height // 160
    x2 = x2 * display.width // 240
    y2 = y2 * display.height // 160
    return x1, y1, x2 - x1, y2 - y1

# Main loop

bus4.write_byte_data(0x41, 0x46)  # set face tracking mode

while True:
    n = bus4.read_byte_data(0x42)
    for i in range(0, n):
        data = bus4.read_i2c_block_data(0x43 + i * 5, 5)
        color = data[0]
        x1 = data[1]
        y1 = data[2]
        x2 = data[3]
        y2 = data[4]
        x, y, w, h = scale(x1, y1, x2, y2)
        fbuf.rect(x, y, w, h, 0)

    speed = n and ((x1 + x2 // 2) - 128) // 4

You should be able to copy the I2C commands along with from smbus import SMBus and they should work in python3 on ev3dev. Don't expect the motor or display stuff to work though.

I had an algorithm for reading multiple objects, but I don't think I saved it. Basically, in the while loop I would read one byte from 0x42, which tells the number of objects then for i in range(0, num): read 5 bytes from 0x43 + num * 5 to read each object. Note: SMBus can only read up to 32 bytes at once, so you can't read all 8 objects in one command.

I2C register definitions are in the User's Manual if you haven't found that already:


This comment has been minimized.

Copy link

commented Apr 6, 2018

Hi @dlech,

thank you for the reply - it helped me a lot and since then I've been playing around with the camera a lot. This is the ev3dev-lang-python code I used to implement the communication (just a single read):

from smbus import SMBus
bus = SMBus(4) # NXTCam-v5 plugged into input port 2, /dev/i2c-in2 -> i2c-4
address = 0x01
bus.write_byte_data(address, 0x41, 0x42)  # set object tracking mode
num = bus.read_byte_data(address, 0x42)  # get number of tracked objects
    if num == 0:
        raise RuntimeError("Zero objects detected.")
    for i in range(0, num):
        data = bus.read_i2c_block_data(address, 0x43 + i * 5, 5)
        # print information on detected objects (rectangles)
        print("color: ", data[0])
        print("x coordinate upper left corner: ", data[1])
        print("y coordinate upper left corner: ", data[2])
        print("x coordinate lower right corner: ", data[3])
        print("x coordinate lower right corner: ", data[4])

One thing I still couldn't figure out though is how to automatically set the mode of the input port to other-i2c. I always have to do that manually on the EV3 brick or when I am connected to the brick via ssh I can run echo other-i2c > /sys/class/lego-port/port1/mode from the command line. (Notice here that the input port marked as number 2 on the EV3 brick internally is port 1.) If I put this command into a script and try executing it with os.system("sh") before running the code from above, I always receive the error PermissionError: [Errno 13] Permission denied when the line bus = SMBus(4) in the python file is executed.

I further tried a solution similar to the one you have implemented above:

port = LegoPort(INPUT_2)
port.mode = 'other-i2c'

However, if I execute this before opening the SMBus for the I2C communication, I always receive the same permission error as above. Remark: In both cases the mode of the input port is correctly changed from auto to other-i2c.

Do you (or anybody else) have an idea what the problem might be and how I could achieve what I am trying to do? Thank you for your help and any kind of further assistance!


This comment has been minimized.

Copy link

commented Apr 8, 2018

I think you may just need to add a delay after setting the mode of the port.

port = LegoPort(INPUT_2)
port.mode = 'other-i2c'

This comment has been minimized.

Copy link

commented Apr 8, 2018

On ev3dev-jessie, the I2C adapter device is not created until you set the mode, so it takes a short time for the udev rules to detect the event and set the permissions of the I2C adapter device.


This comment has been minimized.

Copy link

commented Apr 9, 2018

Perfect - it worked. I love how some solutions are so simple :) Thank you @dlech

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.