Universal Python library for HuskyLens AI camera - supports MicroPython and CPython (Raspberry Pi)
Project description
PyHuskyLens
A universal Python library for connecting the HuskyLens AI camera to robotics platforms. Supports both V1 and V2 hardware with I2C and Serial (UART) interfaces. Works with MicroPython (LEGO, ESP32) and CPython (Raspberry Pi). Perfect for LEGO robotics, ESP32 projects, Raspberry Pi vision systems, and any Python-enabled device.
Table of Contents
- Features
- Installation
- Quick Start
- Hardware Connection
- Example Projects
- API Reference
- Supported Platforms
- Troubleshooting
- License
- Author
Features
- ๐ค Auto-detection: Automatically detects HuskyLens V1 or V2 hardware
- ๐ Dual Interface: Supports both I2C and Serial (UART) communication
- ๐ Dual Platform: Works with MicroPython and CPython (Raspberry Pi)
- ๐ Raspberry Pi Compatible: Native support for Raspberry Pi I2C and Serial
- ๐ฏ Full Algorithm Support: All 14 AI algorithms including face recognition, object tracking, pose detection, hand recognition, and more
- ๐ฆพ Extended Detection: Full V2 support with facial landmarks, 21-point hand keypoints, and 17-point body pose
- ๐พ Memory Optimized: Efficient bytearrays and data structures for MicroPython
- ๐ Backward Compatible: Unified
HuskyLens()constructor works with all platforms - ๐งฉ Clean Architecture: Base class pattern with separate I2C and Serial implementations
- ๐ฆ Platform Agnostic: Works with pybricks-micropython, standard MicroPython, SPIKE, Robot Inventor, and Raspberry Pi CPython
Installation
SPIKE Legacy and Robot Inventor 51515
Copy and paste the contents of pyhuskylens/pyhuskylens.py above your script.
ESP32 / MicroPython
Recommended: Using ViperIDE
The easiest way to install is using ViperIDE:
- Open ViperIDE in your browser
- Connect to your ESP32 device
- Go to Tools โ Install package via link
- Enter:
github:antonvh/PyHuskyLens - Click Install
Alternative: Using mip
Install from your device (if internet-connected):
import mip
mip.install("github:antonvh/PyHuskyLens")
Manual Installation
Copy pyhuskylens/pyhuskylens.py to your device's filesystem.
EV3 with pybricks-micropython
Copy the library file to your project and import directly.
Raspberry Pi (CPython)
Install from PyPI:
pip install pyhuskylens
For I2C support, install smbus2:
pip install pyhuskylens[i2c]
For Serial/UART support, install pyserial:
pip install pyhuskylens[serial]
For both I2C and Serial:
pip install pyhuskylens[all]
Quick Start
Raspberry Pi I2C
from pyhuskylens import HuskyLens, ALGORITHM_OBJECT_RECOGNITION
# Use I2C bus number (0 or 1, typically 1 on Raspberry Pi)
hl = HuskyLens(1) # Automatically uses HuskyLensI2C_RPi
if hl.knock():
print("Connected to HuskyLens V" + str(hl.version))
# Set algorithm
hl.set_alg(ALGORITHM_OBJECT_RECOGNITION)
# Get detected objects
blocks = hl.get_blocks()
print("Found " + str(len(blocks)) + " objects")
for block in blocks:
print("Object at ({},{}) size {}x{}".format(
block.x, block.y, block.width, block.height))
Raspberry Pi Serial
from pyhuskylens import HuskyLens, ALGORITHM_FACE_RECOGNITION
# Use serial port path (typically /dev/ttyUSB0 or /dev/ttyAMA0)
hl = HuskyLens("/dev/ttyUSB0") # Automatically uses HuskyLensSerial_RPi
if hl.knock():
print("Connected!")
hl.set_alg(ALGORITHM_FACE_RECOGNITION)
while True:
blocks = hl.get_blocks(learned=True)
if len(blocks) > 0:
face = blocks[0]
print("Hello, ID: " + str(face.ID))
Simple Object Detection with Auto-Detection
from pyhuskylens import HuskyLens, ALGORITHM_OBJECT_RECOGNITION
# Auto-detects I2C or Serial/UART based on parameter type
# For I2C (ESP32)
from machine import Pin, SoftI2C
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=100000)
hl = HuskyLens(i2c)
# For SPIKE Prime (port string)
# hl = HuskyLens('E')
# For EV3 (Port object)
# from pybricks.parameters import Port
# hl = HuskyLens(Port.S1)
if hl.knock():
print("Connected to HuskyLens V" + str(hl.version))
# Set algorithm
hl.set_alg(ALGORITHM_OBJECT_RECOGNITION)
# Get detected objects
blocks = hl.get_blocks()
print("Found " + str(len(blocks)) + " objects")
for block in blocks:
print("Object at ({},{}) size {}x{}".format(
block.x, block.y, block.width, block.height))
Face Recognition
from pyhuskylens import HuskyLens, ALGORITHM_FACE_RECOGNITION
hl = HuskyLens(i2c) # or port string, or Port object
if hl.knock():
hl.set_alg(ALGORITHM_FACE_RECOGNITION)
while True:
blocks = hl.get_blocks(learned=True) # Only learned faces
if len(blocks) > 0:
face = blocks[0]
print("Hello, ID: " + str(face.ID))
# V2 only: Access facial landmarks
if face.type == "FACE":
print("Eyes: ({},{}) ({},{})".format(
face.leye_x, face.leye_y,
face.reye_x, face.reye_y))
Line Following with Arrows
from pyhuskylens import HuskyLens, ALGORITHM_LINE_TRACKING
hl = HuskyLens(Port.S1) # EV3/Pybricks example
hl.set_alg(ALGORITHM_LINE_TRACKING)
while True:
arrows = hl.get_arrows(learned=True)
if len(arrows) > 0:
arrow = arrows[0]
# Calculate steering based on arrow position
center_offset = arrow.x_head - 160
direction = arrow.direction # Angle in degrees
print("Steer: {} Direction: {}ยฐ".format(center_offset, direction))
Display Text on HuskyLens Screen
from pyhuskylens import HuskyLens, COLOR_GREEN
hl = HuskyLens(i2c)
# Clear any existing text
hl.clear_text()
# Show text (supports both old and new style)
hl.show_text("Hello Robot!", position=(100, 120))
hl.show_text("Status: OK", x=100, y=140, color=COLOR_GREEN)
Advanced: Hand Gesture Recognition (V2 Only)
from pyhuskylens import HuskyLens, ALGORITHM_HAND_RECOGNITION
hl = HuskyLens(i2c)
hl.set_alg(ALGORITHM_HAND_RECOGNITION)
while True:
results = hl.get() # Get all detection data
hands = results['hands'] # Or use HANDS constant
for hand in hands:
# Access 21 hand keypoints
print("Wrist: ({},{})".format(hand.wrist_x, hand.wrist_y))
print("Thumb tip: ({},{})".format(hand.thumb_tip_x, hand.thumb_tip_y))
print("Index tip: ({},{})".format(hand.index_finger_tip_x, hand.index_finger_tip_y))
# Calculate gesture from keypoint positions
thumb_up = hand.thumb_tip_y < hand.thumb_mcp_y
if thumb_up:
print("Thumbs up!")
Advanced: Body Pose Detection (V2 Only)
from pyhuskylens import HuskyLens, ALGORITHM_POSE_RECOGNITION
hl = HuskyLens(i2c)
hl.set_alg(ALGORITHM_POSE_RECOGNITION)
while True:
results = hl.get()
poses = results['poses'] # Or use POSES constant
for pose in poses:
# Access 17 body keypoints
print("Nose: ({},{})".format(pose.nose_x, pose.nose_y))
print("Shoulders: ({},{}) ({},{})".format(
pose.lshoulder_x, pose.lshoulder_y,
pose.rshoulder_x, pose.rshoulder_y))
# Calculate if person is standing/sitting based on keypoints
hip_y = (pose.lhip_y + pose.rhip_y) / 2
shoulder_y = (pose.lshoulder_y + pose.rshoulder_y) / 2
standing = abs(hip_y - shoulder_y) > 50
print("Standing" if standing else "Sitting")
Hardware Connection
I2C Connection
- HuskyLens V1: I2C address
0x32 - HuskyLens V2: I2C address
0x50 - Connections: SDA, SCL, GND, 5V
# Raspberry Pi Example (uses I2C bus number)
hl = HuskyLens(1) # I2C bus 1 (/dev/i2c-1)
# ESP32 Example
from machine import Pin, SoftI2C
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=100000)
hl = HuskyLens(i2c)
Raspberry Pi I2C Setup:
Enable I2C using raspi-config:
sudo raspi-config
# Select: Interface Options โ I2C โ Yes
Verify I2C is working:
sudo apt-get install i2c-tools
i2cdetect -y 1 # Should show 0x32 (V1) or 0x50 (V2)
Serial/UART Connection
- Baudrate: 9600
- HuskyLens Pin 1 (Green) = Tx โ Connect to Robot Rx
- HuskyLens Pin 2 (Blue) = Rx โ Connect to Robot Tx
- Also connect GND and 5V
# Raspberry Pi Example (uses serial port path)
hl = HuskyLens("/dev/ttyUSB0") # USB serial adapter
# or
hl = HuskyLens("/dev/ttyAMA0") # Built-in UART (Raspberry Pi 3/4/5)
# ESP32 Example
from machine import UART
uart = UART(1, baudrate=9600, tx=17, rx=16)
hl = HuskyLens(uart)
# EV3 Pybricks Example
from pybricks.iodevices import UARTDevice
from pybricks.parameters import Port
uart = UARTDevice(Port.S1, 9600)
hl = HuskyLens(uart)
# SPIKE Prime Example (port string auto-handles setup)
hl = HuskyLens('E') # Port E
Raspberry Pi Serial Setup:
For built-in UART (/dev/ttyAMA0), disable the serial console:
sudo raspi-config
# Select: Interface Options โ Serial Port
# "Would you like a login shell accessible over serial?" โ No
# "Would you like the serial port hardware enabled?" โ Yes
sudo reboot
SPIKE/Robot Inventor Wiring
To connect via UART, use a breakout board or solder the included HuskyLens wires to a spare Wedo2 plug pin 5 and 6 (ID1/ID2 lines).
๐ Full SPIKE/MINDSTORMS wiring tutorial
Additional Resources:
Power Supply
Power the HuskyLens with:
- โ USB battery pack (recommended - most stable)
- โ 5V from robot (if sufficient current available)
- โ ๏ธ SPIKE/51515 with LPF power: Use a 3.3V-5V buck converter on M+ (8V) and M- (GND)
โ ๏ธ Warning: Using LPF Motor lines (M1/M2) with firmware 0.5+ may cause random crashes unless powered via USB. Either use external USB power or downgrade to firmware 0.4.7.
Example Projects
HuskyLens connected to LEGO SPIKE Prime for face tracking
๐ Included Examples
Explore the Projects directory for complete working examples:
- EV3 Face Finder - Face tracking with EV3 Pybricks
- EV3 Line Follower - Line tracking robot
- ESP32 PUPRemote - I2C control with ESP32
- SPIKE Face Tracker - Pan/tilt face tracking
- MINDSTORMS Line Follower - SPIKE Prime line following
๐ More Resources
API Reference
Core Classes
HuskyLens(port_or_i2c, baud=9600, debug=False)
Universal constructor with auto-detection. Accepts:
- I2C object (MicroPython): Returns
HuskyLensI2Cinstance - Integer (Raspberry Pi): I2C bus number โ Returns
HuskyLensI2C_RPiinstance - String starting with "/dev/" (Raspberry Pi): Serial port path โ Returns
HuskyLensSerial_RPiinstance - UART object (MicroPython): Returns
HuskyLensSerialinstance - Port string (SPIKE/Inventor): Returns configured
HuskyLensSerial - Port object (Pybricks): Returns configured
HuskyLensSerial
HuskyLensI2C_RPi(bus=1, debug=False)
Raspberry Pi I2C interface using smbus2. Requires pip install smbus2.
HuskyLensSerial_RPi(port, baud=9600, debug=False)
Raspberry Pi Serial interface using pyserial. Requires pip install pyserial.
HuskyLensI2C(i2c, debug=False)
Direct I2C interface constructor (MicroPython).
HuskyLensSerial(uart, debug=False)
Direct Serial/UART interface constructor (MicroPython).
Connection Methods
knock() โ bool
Test connection. Returns True if HuskyLens responds.
get_version() โ str or None
Get firmware version (V1 only).
version property โ int
Hardware version (1 or 2).
Algorithm Control
set_alg(algorithm) โ bool
Switch to specified algorithm. Returns True on success.
set_multi_alg(*algorithms) โ bool
Set 2-5 algorithms simultaneously (V2 only).
Available Algorithms
ALGORITHM_FACE_RECOGNITION = 1 # Detect and recognize faces
ALGORITHM_OBJECT_TRACKING = 2 # Track moving objects
ALGORITHM_OBJECT_RECOGNITION = 3 # Recognize learned objects
ALGORITHM_LINE_TRACKING = 4 # Detect lines and intersections
ALGORITHM_COLOR_RECOGNITION = 5 # Detect colors
ALGORITHM_TAG_RECOGNITION = 6 # Detect AprilTags
ALGORITHM_OBJECT_CLASSIFICATION = 7 # Classify objects (20 classes)
# V2 Only:
ALGORITHM_OCR = 8 # Optical character recognition
ALGORITHM_LICENSE_RECOGNITION = 9 # License plate recognition
ALGORITHM_QR_CODE_RECOGNITION = 10 # QR code detection
ALGORITHM_BARCODE_RECOGNITION = 11 # Barcode scanning
ALGORITHM_FACE_EMOTION_RECOGNITION = 12 # Detect emotions
ALGORITHM_POSE_RECOGNITION = 13 # Body pose (17 keypoints)
ALGORITHM_HAND_RECOGNITION = 14 # Hand pose (21 keypoints)
Detection Methods
get_blocks(algorithm=None, ID=None, learned=False) โ list[Block]
Get detected blocks (faces, objects, poses, hands).
get_arrows(algorithm=None, ID=None, learned=False) โ list[Arrow]
Get detected arrows (lines).
get(algorithm=None, ID=None, learned=False) โ dict
Get all detections. Returns:
{
BLOCKS: [Block, ...], # or 'blocks'
ARROWS: [Arrow, ...], # or 'arrows'
FACES: [Face, ...], # or 'faces'
HANDS: [Hand, ...], # or 'hands'
POSES: [Pose, ...], # or 'poses'
FRAME: None # or 'frame' (legacy)
}
Display Methods
show_text(text, position=(10, 10), x=None, y=None, color=COLOR_WHITE) โ bool
Draw text on HuskyLens screen. Supports both parameter styles:
hl.show_text("Hello", position=(50, 50))
hl.show_text("Hello", x=50, y=50, color=COLOR_GREEN)
draw_text(text, x=10, y=10, color=COLOR_WHITE) โ bool
Alias for show_text() (backward compatibility).
clear_text() โ bool
Clear all text from screen.
draw_rect(x1, y1, x2, y2, color=COLOR_WHITE) โ bool
Draw rectangle (V2 only).
clear_rect() โ bool
Clear rectangles (V2 only).
Color Constants
COLOR_BLACK = 0
COLOR_WHITE = 1
COLOR_RED = 2
COLOR_GREEN = 3
COLOR_BLUE = 4
COLOR_YELLOW = 5
Data Objects
Block
Standard detection block with:
x,y- Center positionwidth,height- DimensionsID- Object ID (if learned)confidence- Detection confidence (V2)name- Object name (V2)content- OCR/QR/Barcode content (V2)learned- Whether object is learnedtype- Detection type ("BLOCK", "FACE", "HAND", "POSE")
Arrow
Line detection with:
x_tail,y_tail- Line startx_head,y_head- Line endID- Line ID (if learned)learned- Whether line is learneddirection- Angle in degreestype- Always "ARROW"
Face (V2 only)
Extends Block with facial landmarks:
leye_x,leye_y- Left eyereye_x,reye_y- Right eyenose_x,nose_y- Nose tiplmouth_x,lmouth_y- Left mouth cornerrmouth_x,rmouth_y- Right mouth corner
Hand (V2 only)
Extends Block with 21 keypoints:
- Wrist:
wrist_x,wrist_y - Thumb:
thumb_cmc_*,thumb_mcp_*,thumb_ip_*,thumb_tip_* - Index:
index_finger_mcp_*,index_finger_pip_*,index_finger_dip_*,index_finger_tip_* - Middle:
middle_finger_mcp_*,middle_finger_pip_*,middle_finger_dip_*,middle_finger_tip_* - Ring:
ring_finger_mcp_*,ring_finger_pip_*,ring_finger_dip_*,ring_finger_tip_* - Pinky:
pinky_mcp_*,pinky_pip_*,pinky_dip_*,pinky_tip_*
Pose (V2 only)
Extends Block with 17 body keypoints:
nose_x,nose_yleye_x,leye_y,reye_x,reye_ylear_x,lear_y,rear_x,rear_ylshoulder_*,rshoulder_*lelbow_*,relbow_*lwrist_*,rwrist_*lhip_*,rhip_*lknee_*,rknee_*lankle_*,rankle_*
Utility Functions
clamp_int(value, min_val=-100, max_val=100) โ int
Clamp value to specified range.
Supported Platforms
- โ Raspberry Pi (3/4/5/Zero 2W) with CPython 3.7+
- โ ESP32 with MicroPython
- โ LEGO SPIKE Prime / Essential (with MicroPython firmware)
- โ LEGO MINDSTORMS Robot Inventor 51515
- โ LEGO MINDSTORMS EV3 (with pybricks-micropython)
- โ Raspberry Pi Pico / Pico W
- โ Any MicroPython board with I2C or UART support
Troubleshooting
Connection Issues
"No device found" or knock() returns False
- โ Check I2C address: 0x32 (V1) or 0x50 (V2)
- โ Verify UART wiring: Green=Tx, Blue=Rx (check you haven't swapped them)
- โ Ensure 5V power is connected
- โ Try
hl = HuskyLens(i2c, debug=True)to see communication details
Random crashes or freezes
- โ ๏ธ Use external USB power instead of motor power
- โ ๏ธ Check voltage stability (use multimeter)
- โ ๏ธ For SPIKE/51515: Consider downgrading to firmware 0.4.7
Detection Issues
No data returned from get_blocks() or get_arrows()
- โ Call
knock()first to verify connection - โ Check that algorithm is set with
set_alg() - โ Ensure objects are learned (press and hold button on HuskyLens)
- โ Check if
learned=Truefilter is too restrictive
Slow performance
- โ I2C is generally faster than UART
- โ Reduce detection frequency in your loop
- โ Use specific filters (
ID=,learned=True) to reduce data - โ V2 hardware is generally faster than V1
Platform-Specific
Raspberry Pi
- I2C is automatically detected when passing an integer (bus number)
- Serial is automatically detected when passing a path starting with "/dev/"
- Requires
smbus2for I2C:pip install pyhuskylens[i2c] - Requires
pyserialfor Serial:pip install pyhuskylens[serial] - Enable I2C/Serial in
raspi-configbefore use - Built-in UART on GPIO 14/15 is
/dev/ttyAMA0(Raspberry Pi 3/4/5)
SPIKE Prime / Robot Inventor
- Port initialization is handled automatically by
HuskyLens('E') - Wait ~2 seconds after initialization for bootup
- Use
debug=Falseto reduce memory usage
ESP32
- Use
SoftI2Cif hardware I2C has conflicts - Default I2C pins: SCL=22, SDA=21
- Reduce I2C frequency if communication errors occur:
freq=100000or lower
EV3 Pybricks
- UART is the only option (no I2C support)
- Use
UARTDevice(Port.S1, 9600) - Ensure pybricks-micropython v2.0+
Performance Notes
- Frame Rate: Typically 10-20 FPS depending on algorithm and platform
- I2C vs UART: I2C generally 2-3x faster than UART
- V1 vs V2: V2 has faster processor and more algorithms
- Memory: Uses efficient bytearrays, suitable for memory-constrained devices
- Detection Range: ~20-200cm depending on object size and algorithm
License
MIT License - See LICENSE file for details
Author
Anton Vanhoucke
Anton's Mindstorms
Contributing: Pull requests welcome! For major changes, please open an issue first.
Issues: Report bugs or request features via GitHub Issues
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyhuskylens-2.3.0.tar.gz.
File metadata
- Download URL: pyhuskylens-2.3.0.tar.gz
- Upload date:
- Size: 30.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4733b7421df8c75061d8df02a13f43720f55bcdc284c58f6541a8160aa080fb5
|
|
| MD5 |
823ef238849c6c773e1b21886c90df1e
|
|
| BLAKE2b-256 |
ca7dcb090eadf1dd52a4c164f2fab465907ff3d1e120be136c7cc5faa8f93bd5
|
File details
Details for the file pyhuskylens-2.3.0-py3-none-any.whl.
File metadata
- Download URL: pyhuskylens-2.3.0-py3-none-any.whl
- Upload date:
- Size: 20.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b935ae9eb71972a47e2c3638f8178e99c6cfb2224fdc8607b5c05733cfc69fa2
|
|
| MD5 |
95922cecc930d96b5d98f9cd80e90846
|
|
| BLAKE2b-256 |
286fb329d3213764e17f9ad2de2ad4237eff573b63b86ae847277f0e612b6625
|