Files
RadioPhotonic_PCB_PC_software/README.md
2026-02-18 17:44:18 +03:00

213 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RadioPhotonic PCB — Laser Controller
GUI application and embeddable Python module for controlling a dual-laser board
over UART (115 200 baud). Designed to run on a Raspberry Pi or any Linux machine.
---
## Project structure
```
.
├── _device_main.py # GUI application entry point
├── gui.py # FreeSimpleGUI layout definition
├── device_interaction.py # High-level device commands (legacy)
├── device_commands.py # Low-level protocol helpers (legacy)
├── device_conversion.py # Physical-unit conversion formulas (legacy)
├── laser_control/ # Standalone embeddable module
│ ├── __init__.py # Public API
│ ├── controller.py # LaserController class
│ ├── protocol.py # Command encoding / response decoding
│ ├── validators.py # Input validation
│ ├── conversions.py # Physical-unit conversions
│ ├── models.py # Dataclasses (Measurements, DeviceStatus, …)
│ ├── constants.py # Protocol constants and physical limits
│ ├── exceptions.py # Exception hierarchy
│ └── example_usage.py # Usage examples
├── tests/ # pytest test suite (75 tests)
│ ├── conftest.py
│ ├── test_validation.py
│ ├── test_protocol.py
│ └── test_integration.py
├── pyproject.toml # Package metadata (laser_control)
├── run # Launch script for the GUI app
└── deploy # First-time environment setup script
```
---
## Setting up the virtual environment
### First-time setup
```bash
# 1. Create virtual environment
python3 -m venv .venv
# 2. Activate it
source .venv/bin/activate
# 3. Install GUI and serial dependencies
pip install FreeSimpleGUI pyserial
# 4. Install laser_control as an editable package
# (required for imports to work in any subdirectory)
pip install -e .
# 5. Install pytest (for running tests)
pip install pytest
```
> **Note:** Steps 35 can be run via the existing `deploy` script (steps 13),
> then manually run `pip install -e . && pip install pytest` once inside the venv.
### Every subsequent session
```bash
source .venv/bin/activate
```
---
## Running the GUI application
```bash
source .venv/bin/activate
./run
# or directly:
python3 _device_main.py
```
The application auto-detects the USB serial port. If more than one port is
present, the first one found is used.
---
## Running the tests
```bash
source .venv/bin/activate
python3 -m pytest tests/ -v
```
Expected result: **75 passed**.
---
## Running the usage example
```bash
source .venv/bin/activate
# Auto-detect port:
python3 laser_control/example_usage.py
# Specify port explicitly:
python3 laser_control/example_usage.py /dev/ttyUSB0
```
---
## Embedding laser_control in another application
After `pip install -e .` (or copying the `laser_control/` folder into your
project and running `pip install -e .` there), import as follows:
```python
from laser_control import (
LaserController,
VariationType,
ValidationError,
CommunicationError,
)
# --- Manual mode ---
with LaserController(port='/dev/ttyUSB0') as ctrl:
try:
ctrl.set_manual_mode(
temp1=25.0, # °C [15 … 40]
temp2=30.0, # °C [15 … 40]
current1=40.0, # mA [15 … 60]
current2=35.0, # mA [15 … 60]
)
data = ctrl.get_measurements()
if data:
print(f"3.3 V rail: {data.voltage_3v3:.3f} V")
print(f"Laser 1 temperature: {data.temp1:.2f} °C")
except ValidationError as e:
print(f"Bad parameter: {e}")
except CommunicationError as e:
print(f"Device not responding: {e}")
# --- Current variation mode ---
def on_data(m):
print(f"I1={m.current1:.3f} mA T1={m.temp1:.2f} °C")
with LaserController(port=None, on_data=on_data) as ctrl: # port=None → auto-detect
ctrl.start_variation(
variation_type=VariationType.CHANGE_CURRENT_LD1,
params={
'min_value': 20.0, # mA
'max_value': 50.0, # mA
'step': 0.5, # mA [0.002 … 0.5]
'time_step': 50, # µs [20 … 100]
'delay_time': 5, # ms [3 … 10]
'static_temp1': 25.0,
'static_temp2': 30.0,
'static_current1': 35.0,
'static_current2': 35.0,
}
)
import time; time.sleep(2)
ctrl.stop_task()
```
### Parameter limits
| Parameter | Min | Max | Unit |
|---|---|---|---|
| Temperature (T1, T2) | 15.0 | 40.0 | °C |
| Current (I1, I2) | 15.0 | 60.0 | mA |
| Current variation step | 0.002 | 0.5 | mA |
| Temperature variation step | 0.05 | 1.0 | °C |
| Time step | 20 | 100 | µs |
| Delay time | 3 | 10 | ms |
### Exception hierarchy
```
LaserControlError
├── ValidationError
│ ├── TemperatureOutOfRangeError
│ ├── CurrentOutOfRangeError
│ └── InvalidParameterError
├── CommunicationError
│ ├── PortNotFoundError
│ ├── DeviceNotRespondingError
│ ├── CRCError
│ └── ProtocolError
└── DeviceError
├── DeviceOverheatingError
├── PowerSupplyError
└── DeviceStateError
```
---
## Device output
Each measurement response contains:
| Field | Description | Unit |
|---|---|---|
| `temp1`, `temp2` | Laser temperatures | °C |
| `temp_ext1`, `temp_ext2` | External thermistor temperatures | °C |
| `current1`, `current2` | Photodiode currents | mA |
| `voltage_3v3` | 3.3 V power rail | V |
| `voltage_5v1`, `voltage_5v2` | 5 V power rails | V |
| `voltage_7v0` | 7 V power rail | V |