adding files
This commit is contained in:
282
docs/DRO.md
Normal file
282
docs/DRO.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# Digital Read Out (DRO) Application
|
||||
|
||||
The `dro.py` file implements a Digital Read Out system for a lathe. It displays the current position of the lathe tool on two axes (X and Z) by reading encoder data from an Arduino via I2C communication.
|
||||
|
||||
## Overview
|
||||
|
||||
The application follows the **Model-View-Controller (MVC)** architectural pattern, which separates concerns:
|
||||
- **Model**: Manages the state of the axes and their positions
|
||||
- **View**: Displays the positions in a Tkinter GUI
|
||||
- **Controller**: Handles user input and I2C communication
|
||||
|
||||
## Architecture
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
Arduino (Encoder Data)
|
||||
↓ (I2C)
|
||||
Controller (Serial Communication) → Model (Position Calculation)
|
||||
↓ ↓
|
||||
View (GUI Update) ← ← ← ← ← ← ← ← ← ← Observers
|
||||
```
|
||||
|
||||
## Classes
|
||||
|
||||
### Axis
|
||||
|
||||
Represents a single axis (X or Z) with position, scale, and offset.
|
||||
|
||||
**Attributes:**
|
||||
- `_position`: Current position in mm
|
||||
- `_scale`: Scale factor (mm per encoder step)
|
||||
- `_offset`: Offset applied to position (mm)
|
||||
- `_name`: Axis identifier ('x' or 'z')
|
||||
|
||||
**Methods:**
|
||||
- `set_position(pos)`: Set the raw position
|
||||
- `get_position()`: Get the raw position
|
||||
- `set_scale(scale)`: Set the scale factor
|
||||
- `get_scale()`: Get the scale factor
|
||||
- `set_offset(offset)`: Set the offset
|
||||
- `get_offset()`: Get the offset
|
||||
|
||||
### Model
|
||||
|
||||
Manages the state of both axes and notifies observers of changes. Implements the **Observer pattern** for MVC binding.
|
||||
|
||||
**Enums:**
|
||||
- `XMode.RADIUS (0)`: X axis displays radius (default)
|
||||
- `XMode.DIAMETER (1)`: X axis displays diameter
|
||||
- `Updated.POS_X (0)`: X position changed
|
||||
- `Updated.POS_Z (1)`: Z position changed
|
||||
- `Updated.X_MODE (2)`: X mode (radius/diameter) changed
|
||||
- `Updated.FULLSCREEN (3)`: Fullscreen state changed
|
||||
|
||||
**Key Methods:**
|
||||
- `attach(observer)`: Register an observer (typically the View)
|
||||
- `notify(updated)`: Notify all observers of changes
|
||||
- `steps_to_position(axis, steps)`: Convert encoder steps to millimeters
|
||||
- `set_position(axis, pos)`: Update a position (notifies if changed)
|
||||
- `set_offset(axis, offset)`: Set the zero offset for calibration
|
||||
- `get_effective_position(axis)`: Get position with offset applied; converts diameter to radius if needed
|
||||
- `set_toggle_x_mode()`: Toggle between radius and diameter display
|
||||
- `set_scale(axis, scale)`: Set the steps-to-mm conversion factor
|
||||
|
||||
**Special Behavior:**
|
||||
- Position updates only trigger notifications if the change is ≥ 0.005 mm (prevents chatter)
|
||||
- When X axis is in DIAMETER mode, displayed position is doubled
|
||||
|
||||
### Controller
|
||||
|
||||
Handles user interaction and I2C communication with the Arduino.
|
||||
|
||||
**Hardware:**
|
||||
- I2C Bus: 1 (standard Raspberry Pi I2C)
|
||||
- Arduino Address: 0x08
|
||||
|
||||
**Data Format:**
|
||||
- Reads 4 bytes from Arduino every poll cycle
|
||||
- Bytes 0-1: X position (little-endian signed 16-bit integer)
|
||||
- Bytes 2-3: Z position (little-endian signed 16-bit integer)
|
||||
|
||||
**Methods:**
|
||||
- `poll_i2c_data()`: Read encoder positions from Arduino via I2C
|
||||
- `handle_x_position_update(steps)`: Process X encoder data
|
||||
- `handle_z_position_update(steps)`: Process Z encoder data
|
||||
- `handle_btn_x0_press()`: Set X zero point (sets offset to -current position)
|
||||
- `handle_btn_z0_press()`: Set Z zero point
|
||||
- `handle_btn_toggle_x_mode()`: Switch between radius/diameter display
|
||||
- `hanlde_btn_x()`: Open dialog to manually set X position
|
||||
- `hanlde_btn_z()`: Open dialog to manually set Z position
|
||||
- `toggle_fullscreen()`: Toggle fullscreen display (F11)
|
||||
- `end_fullscreen()`: Exit fullscreen mode (Escape)
|
||||
- `handle_btn_calc()`: Launch system calculator (galculator)
|
||||
- `shutdown()`: Shutdown the system (produces clean shutdown)
|
||||
|
||||
### View
|
||||
|
||||
Tkinter GUI displaying positions, buttons, and status. Acts as an observer of the Model.
|
||||
|
||||
**GUI Layout:**
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ X Position │ [X] [X_0] │
|
||||
│ Z Position │ [Z] [Z_0] │
|
||||
│ Mode │ │
|
||||
│ │ [r/D] [Calc] [Off]│
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Display Features:**
|
||||
- Large font (80pt) for easy reading from distance
|
||||
- Green text on black background for visibility
|
||||
- Real-time position updates at 10 Hz
|
||||
- Mode indicator (R for radius, D for diameter)
|
||||
|
||||
**Button Functions:**
|
||||
- **X / Z**: Open dialog to set position
|
||||
- **X_0 / Z_0**: Set zero point (calibrate)
|
||||
- **r/D**: Toggle radius/diameter mode
|
||||
- **Calc**: Launch calculator
|
||||
- **Power**: Shutdown system
|
||||
|
||||
**Keyboard Shortcuts:**
|
||||
- **F11**: Toggle fullscreen
|
||||
- **Escape**: Exit fullscreen
|
||||
- **A/Z** (test mode): Rotate X encoder clockwise/counterclockwise
|
||||
- **S/X** (test mode): Rotate Z encoder clockwise/counterclockwise
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Startup
|
||||
|
||||
```bash
|
||||
python3 dro.py
|
||||
```
|
||||
|
||||
### Command Line Options
|
||||
|
||||
```bash
|
||||
# Maximize window on startup
|
||||
python3 dro.py --zoomed
|
||||
|
||||
# Run in test mode (no I2C communication, use keyboard to simulate encoders)
|
||||
python3 dro.py --test
|
||||
|
||||
# Both options
|
||||
python3 dro.py --zoomed --test
|
||||
```
|
||||
|
||||
### Typical Workflow
|
||||
|
||||
1. **Startup**: Application connects to Arduino via I2C and displays current encoder positions
|
||||
2. **Zero Axes**: Press X_0 and Z_0 buttons at the tool's starting position
|
||||
3. **Move Tool**: As you move the tool, positions update in real-time
|
||||
4. **Set Position**: Click X or Z button to set a specific position (useful for manual adjustments)
|
||||
5. **Toggle Mode**: Press r/D to switch X axis between radius and diameter display
|
||||
6. **Shutdown**: Click the power button or use the system menu
|
||||
|
||||
### Offset/Zero Calibration
|
||||
|
||||
The offset mechanism allows setting the zero point at any position:
|
||||
|
||||
```
|
||||
Displayed Position = Raw Position + Offset
|
||||
```
|
||||
|
||||
When you press X_0 or Z_0, the system sets:
|
||||
```
|
||||
Offset = -Current_Position
|
||||
```
|
||||
|
||||
This makes the current display read zero.
|
||||
|
||||
### Radius vs Diameter Mode
|
||||
|
||||
The X axis can display in two modes:
|
||||
|
||||
- **Radius (r)**: Shows actual distance from spindle centerline
|
||||
- **Diameter (D)**: Shows diameter (actual = radius × 2)
|
||||
|
||||
The Model automatically converts when displaying:
|
||||
```
|
||||
Diameter Display = Radius × 2
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Default Scales
|
||||
|
||||
```python
|
||||
model.set_scale('x', -2.5/200) # -12.5 mm per 1000 steps (negative = flip direction)
|
||||
model.set_scale('z', 90/1000) # 0.09 mm per step
|
||||
```
|
||||
|
||||
These calibration values should be adjusted based on your encoder specifications:
|
||||
- Negative X scale flips the direction to match lathe conventions
|
||||
- Scale = (Distance Travel in mm) / (Encoder Steps)
|
||||
|
||||
### Update Frequency
|
||||
|
||||
- GUI updates every 100ms (10 Hz)
|
||||
- I2C polling rate matches GUI updates
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Python Packages
|
||||
- `tkinter`: GUI framework (built-in with Python)
|
||||
- `smbus2`: I2C communication (falls back to fake_smbus.py if not available)
|
||||
- Standard library: `enum`, `subprocess`, `getopt`, `sys`, `shutil`, `logging`
|
||||
|
||||
### Hardware
|
||||
- Raspberry Pi (tested on Pi 4)
|
||||
- Arduino Nano (with I2C firmware at address 0x08)
|
||||
- 2 Rotary encoders connected to Arduino
|
||||
|
||||
### System
|
||||
- `galculator`: Calculator application (optional)
|
||||
- `sudo` access for shutdown command
|
||||
|
||||
## Error Handling
|
||||
|
||||
The application gracefully handles several error conditions:
|
||||
|
||||
### I2C Communication Errors
|
||||
```python
|
||||
try:
|
||||
data = self._bus.read_i2c_block_data(self._address, 0, 4)
|
||||
except IOError as e:
|
||||
logger.error(f"I2C read error: {e}")
|
||||
except OSError as e:
|
||||
logger.error(f"I2C OS error: {e}")
|
||||
```
|
||||
|
||||
Errors are logged but don't crash the application. The last known position is retained.
|
||||
|
||||
### Missing Dependencies
|
||||
If `smbus2` is not installed, the application falls back to the local `RPi/fake_smbus.py`:
|
||||
```python
|
||||
try:
|
||||
import smbus2
|
||||
except ImportError:
|
||||
import RPi.fake_smbus as smbus2
|
||||
logger.warning('smbus2 not available; using fake smbus2.py')
|
||||
```
|
||||
|
||||
## Testing Mode
|
||||
|
||||
The `--test` flag enables keyboard simulation of encoder rotation:
|
||||
|
||||
```
|
||||
X Axis:
|
||||
A = Rotate clockwise (increase X)
|
||||
Z = Rotate counterclockwise (decrease X)
|
||||
|
||||
Z Axis:
|
||||
S = Rotate clockwise (increase Z)
|
||||
X = Rotate counterclockwise (decrease Z)
|
||||
```
|
||||
|
||||
This allows testing the GUI without physical encoders or Arduino.
|
||||
|
||||
## Known Issues / Notes
|
||||
|
||||
- Method name typo: `hanlde_btn_x()` and `hanlde_btn_z()` should be `handle_btn_x()` and `handle_btn_z()`
|
||||
- Position updates use a 0.005 mm hysteresis threshold (prevents noise-induced updates)
|
||||
- Fullscreen mode requires the Tkinter window to support the platform's fullscreen API
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- GUI updates are non-blocking and scheduled on the Tkinter event loop
|
||||
- I2C reads are synchronous and run every 100ms (10 Hz update rate)
|
||||
- Position filtering reduces redundant updates by ~99% in typical operation
|
||||
- StringVar widgets minimize GUI redraws by only updating when values change
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
- Add tool offset/wear compensation
|
||||
- Support more than 2 axes
|
||||
- Persistent configuration file for scales and offsets
|
||||
- Network interface for remote monitoring
|
||||
- Data logging of position history
|
||||
Reference in New Issue
Block a user