UC2-REST Python Interface
Advanced documentation for the UC2-REST Python library, including API reference, integration guides, and custom development.
Overview
UC2-REST is the Python interface library that provides high-level control of UC2 hardware through the UC2-ESP32 firmware. It serves as the bridge between Python applications (including ImSwitch) and the low-level hardware control.
Key Features
- Object-Oriented API: Intuitive Python interface for hardware control
- Dual Communication: USB Serial and WiFi/HTTP support
- Error Handling: Robust communication with automatic retry
- ImSwitch Integration: Native support for ImSwitch microscopy software
- Extensible: Easy to add custom device managers and protocols
Available Documentation
Getting Started
- Installation Guide - Install UC2-REST library
- Quick Start - Basic usage examples
- API Overview - High-level API introduction
Core Documentation
- Communication Introduction - Basic communication concepts
- ESP32 Messaging - Message handling system
- Motor Control - Motor control examples
- Command Sending - Command interface details
Advanced Topics
- API Reference - Complete API documentation
- Integration Guide - Integrate with other software
- Custom Managers - Create custom device managers
- Protocol Documentation - Communication protocol details
Quick Reference
Basic Connection
from UC2REST import UC2Client
# USB Serial connection
client = UC2Client(serialport="/dev/ttyUSB0")
# WiFi connection
client = UC2Client(host="192.168.1.100", port=31950)
# Check connection
if client.is_connected:
print("Connected to UC2-ESP32")
Hardware Control
# LED control
client.led.set_led(channel=1, intensity=100)
client.led.set_led_array([100, 50, 75, 0])
# Motor control
client.stage.move_x(1000)
client.stage.move_xyz(x=500, y=500, z=100)
client.stage.home_xyz()
# Laser control
client.laser.set_laser(channel=1, intensity=50)
client.laser.turn_off_all()
# Sensor reading
sensors = client.sensor.get_sensor_data()
position = client.stage.get_position()
Architecture
Class Hierarchy
UC2Client
├── SerialManager (USB communication)
├── HTTPManager (WiFi communication)
├── LEDManager (LED control)
├── StageManager (Motor control)
├── LaserManager (Laser control)
├── SensorManager (Sensor reading)
└── StateManager (System status)
Communication Flow
Python Application
↓
UC2Client
↓
Communication Manager (Serial/HTTP)
↓
JSON Protocol
↓
UC2-ESP32 Firmware
↓
Hardware Components
Device Managers
LED Manager
class LEDManager:
def set_led(self, channel, intensity):
"""Set individual LED intensity"""
def set_led_array(self, intensities):
"""Set multiple LED intensities"""
def get_led_status(self):
"""Get current LED status"""
Stage Manager
class StageManager:
def move_x(self, steps):
"""Move X axis by specified steps"""
def move_xyz(self, x=0, y=0, z=0):
"""Move multiple axes simultaneously"""
def set_position(self, x=None, y=None, z=None):
"""Set absolute position"""
def home_xyz(self):
"""Home all axes"""
def get_position(self):
"""Get current position"""
Laser Manager
class LaserManager:
def set_laser(self, channel, intensity):
"""Set laser power"""
def turn_off_all(self):
"""Emergency laser shutdown"""
def get_laser_info(self):
"""Get laser capabilities"""
Integration Examples
ImSwitch Configuration
{
"rs232devices": {
"ESP32": {
"managerName": "ESP32Manager",
"managerProperties": {
"serialport": "/dev/ttyUSB0",
"host_": "192.168.1.100"
}
}
},
"positioners": {
"ESP32Stage": {
"managerName": "ESP32StageManager",
"managerProperties": {
"rs232device": "ESP32"
},
"axes": ["X", "Y", "Z"],
"forScanning": true
}
}
}
Custom Device Manager
from UC2REST import UC2Client
from imswitch.imcontrol.model.interfaces import DeviceManager
class CustomUC2Manager(DeviceManager):
def __init__(self, deviceInfo, name, **kwargs):
super().__init__(deviceInfo, name, **kwargs)
# Initialize UC2-REST client
self.client = UC2Client(
serialport=deviceInfo.managerProperties.get('serialport'),
host=deviceInfo.managerProperties.get('host')
)
def custom_function(self, parameters):
"""Implement custom functionality"""
return self.client.send_command({
"task": "/custom_act",
"parameters": parameters
})
Jupyter Notebook Integration
# Interactive microscopy control
import ipywidgets as widgets
from IPython.display import display
def create_motor_controls(client):
"""Create interactive motor controls"""
# Movement buttons
move_x_plus = widgets.Button(description='X+')
move_x_minus = widgets.Button(description='X-')
# Step size slider
step_size = widgets.IntSlider(value=100, min=10, max=1000)
def on_move_x_plus(b):
client.stage.move_x(step_size.value)
def on_move_x_minus(b):
client.stage.move_x(-step_size.value)
move_x_plus.on_click(on_move_x_plus)
move_x_minus.on_click(on_move_x_minus)
return widgets.VBox([
step_size,
widgets.HBox([move_x_minus, move_x_plus])
])
# Create and display controls
controls = create_motor_controls(client)
display(controls)
Advanced Usage
Error Handling
from UC2REST import UC2RESTError
import serial
try:
client = UC2Client(serialport="/dev/ttyUSB0")
client.stage.move_x(1000)
except UC2RESTError as e:
print(f"UC2-REST error: {e}")
except serial.SerialException as e:
print(f"Serial communication error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Custom Commands
def send_custom_command(client, command_data):
"""Send custom JSON command"""
try:
response = client.send_command(command_data)
if response.get("return") == 1:
return response
else:
raise UC2RESTError(f"Command failed: {response}")
except Exception as e:
print(f"Communication error: {e}")
return None
# Example usage
result = send_custom_command(client, {
"task": "/custom_task",
"parameter1": "value1",
"parameter2": 42
})
Performance Optimization
class OptimizedController:
def __init__(self, client):
self.client = client
self.position_cache = {"x": 0, "y": 0, "z": 0}
def move_relative(self, dx=0, dy=0, dz=0):
"""Move relative with position caching"""
# Update cached position
self.position_cache["x"] += dx
self.position_cache["y"] += dy
self.position_cache["z"] += dz
# Send movement command
self.client.stage.move_xyz(x=dx, y=dy, z=dz)
def get_cached_position(self):
"""Get position from cache (faster than querying hardware)"""
return self.position_cache.copy()
def sync_position(self):
"""Synchronize cache with actual hardware position"""
actual_pos = self.client.stage.get_position()
self.position_cache.update(actual_pos)
return actual_pos
Custom Protocol Development
Protocol Extension
class CustomProtocol:
def __init__(self, client):
self.client = client
def batch_commands(self, commands):
"""Execute multiple commands efficiently"""
batch_command = {
"task": "/batch_act",
"commands": commands
}
return self.client.send_command(batch_command)
def stream_data(self, duration, interval):
"""Stream sensor data for specified duration"""
stream_command = {
"task": "/stream_start",
"duration": duration,
"interval": interval
}
# Start streaming
response = self.client.send_command(stream_command)
if response.get("return") == 1:
# Read streamed data
data = []
for _ in range(int(duration / interval)):
reading = self.client.sensor.get_sensor_data()
data.append(reading)
time.sleep(interval)
return data
else:
raise UC2RESTError("Failed to start data streaming")
Testing and Validation
Unit Tests
import unittest
from UC2REST import UC2Client
class TestUC2REST(unittest.TestCase):
def setUp(self):
self.client = UC2Client(serialport="/dev/ttyUSB0")
def test_connection(self):
"""Test basic connection"""
self.assertTrue(self.client.is_connected)
def test_led_control(self):
"""Test LED control"""
# Turn LED on
self.client.led.set_led(channel=1, intensity=100)
# Turn LED off
self.client.led.set_led(channel=1, intensity=0)
# Test should not raise exceptions
self.assertTrue(True)
def test_stage_movement(self):
"""Test stage movement"""
original_pos = self.client.stage.get_position()
# Move and return
self.client.stage.move_x(100)
time.sleep(1)
self.client.stage.move_x(-100)
time.sleep(1)
final_pos = self.client.stage.get_position()
# Should return to approximately original position
self.assertAlmostEqual(
original_pos["x"], final_pos["x"], delta=10
)
if __name__ == "__main__":
unittest.main()
Performance Benchmarks
import time
import statistics
def benchmark_communication_speed(client, n_commands=100):
"""Benchmark communication speed"""
times = []
for _ in range(n_commands):
start = time.time()
client.state.get_state()
end = time.time()
times.append(end - start)
return {
"mean": statistics.mean(times),
"median": statistics.median(times),
"stdev": statistics.stdev(times),
"commands_per_second": 1.0 / statistics.mean(times)
}
# Run benchmark
results = benchmark_communication_speed(client)
print(f"Communication speed: {results['commands_per_second']:.1f} commands/sec")
Troubleshooting
Common Issues
Connection Problems:
# Check available serial ports
import serial.tools.list_ports
ports = serial.tools.list_ports.comports()
for port in ports:
print(f"{port.device}: {port.description}")
# Test with different parameters
try:
client = UC2Client(serialport="/dev/ttyUSB0", baudrate=115200, timeout=2.0)
except Exception as e:
print(f"Connection failed: {e}")
Communication Timeouts:
# Increase timeout for slow operations
client = UC2Client(serialport="/dev/ttyUSB0", timeout=5.0)
# Implement retry logic
def robust_command(client, command_func, max_retries=3):
for attempt in range(max_retries):
try:
return command_func()
except Exception as e:
if attempt == max_retries - 1:
raise e
time.sleep(1)
Debug Mode:
# Enable debug output
client = UC2Client(serialport="/dev/ttyUSB0", DEBUG=True)
# All communication will be logged
client.stage.move_x(1000)
# Output: [DEBUG] Sending: {"task": "/motor_act", ...}
# [DEBUG] Received: {"return": 1, ...}
Contributing
Development Setup
# Clone repository
git clone https://github.com/openUC2/UC2-REST
cd UC2-REST
# Install in development mode
pip install -e .
# Install development dependencies
pip install -r requirements-dev.txt
Code Style
- Follow PEP 8 style guidelines
- Use type hints where possible
- Document all public methods
- Include docstring examples
Testing
# Run unit tests
python -m pytest tests/
# Run with coverage
python -m pytest --cov=UC2REST tests/
# Run integration tests (requires hardware)
python -m pytest tests/integration/
Related Resources
- UC2-ESP32 Firmware - Firmware documentation
- ImSwitch Integration - ImSwitch usage guide
- Hardware Interfaces - Hardware components