# Arduino I2C Protocol This document describes the I2C communication protocol between the Raspberry Pi (DRO application) and the Arduino (encoder interface). ## Hardware Setup ### I2C Configuration - **Bus**: I2C Bus 1 (standard Raspberry Pi I2C) - **Arduino Slave Address**: 0x08 - **Data Rate**: Standard (100 kHz) or Fast (400 kHz) - **Pull-up Resistors**: 4.7 kΩ (typical I2C standards) ### Connections ``` Raspberry Pi Arduino GPIO2 (SDA) <-> SDA GPIO3 (SCL) <-> SCL GND <- GND 5V (optional)-> 5V (if Arduino powered separately) ``` ## Data Format The Arduino transmits encoder positions as a 4-byte block: ### Memory Layout ``` Byte 0-1: X Position (little-endian signed 16-bit integer) Byte 2-3: Z Position (little-endian signed 16-bit integer) ``` ### Example If encoder reads: - X encoder: +5000 steps - Z encoder: -200 steps The transmitted bytes would be: ``` Byte 0: 0x88 (LSB of 5000) Byte 1: 0x13 (MSB of 5000) Byte 2: 0x38 (LSB of -200) Byte 3: 0xFF (MSB of -200 in two's complement) ``` ### Python Parsing ```python import struct # Read from I2C data = bus.read_i2c_block_data(address, 0, 4) # Convert to signed integers x_position = int.from_bytes(bytes(data[0:2]), 'little', signed=True) z_position = int.from_bytes(bytes(data[2:4]), 'little', signed=True) # Or using struct: x_pos, z_pos = struct.unpack('> 8); buffer[2] = (byte)z_position; buffer[3] = (byte)(z_position >> 8); Wire.write(buffer, 4); } ``` ## Encoder Interface The Arduino handles the low-level encoder reading: ### Encoder Connection ``` Rotary Encoder (2-bit Gray code or quadrature) │ ├─ Signal A ──→ Arduino Interrupt Pin ├─ Signal B ──→ Arduino Pin └─ GND ──────→ Arduino GND ``` ### Common Encoder Types 1. **Quadrature Encoder** - 2 signals 90° out of phase - Allows detection of direction and speed - Typical: KY-040 module 2. **Incremental Encoder** - Pulse + Direction signals - Requires external direction determination 3. **Absolute Encoder** - Maintains position across power cycles - More complex protocol (often SPI/USB) ## Error Handling ### Arduino Side - **Buffer Overrun**: Ensure encoder ISR is fast (< 100 µs) - **I2C Collision**: Wire library handles this automatically - **Power Loss**: Position may reset unless using volatile storage ### Raspberry Pi Side The DRO application handles: ```python try: data = self._bus.read_i2c_block_data(self._address, 0, 4) except IOError as e: # I2C bus error (timeout, NACK, collision) logger.error(f"I2C read error: {e}") except OSError as e: # System-level I2C error logger.error(f"I2C OS error: {e}") ``` If a read fails, the last known position is retained. ## Debugging I2C Communication ### Check I2C Bus ```bash # List I2C devices i2cdetect -y 1 # Expected output for Arduino at 0x08: # 0 1 2 3 4 5 6 7 8 9 a b c d e f # 00: -- -- -- -- -- -- -- -- 08 -- -- -- -- ``` ### Manual Read Test ```bash # Read 4 bytes from address 0x08, register 0 i2cget -y 1 0x08 0 i 4 # Expected output: four hex bytes ``` ### Python Test ```python import smbus2 bus = smbus2.SMBus(1) data = bus.read_i2c_block_data(0x08, 0, 4) print(f"Raw bytes: {[hex(b) for b in data]}") x = int.from_bytes(bytes(data[0:2]), 'little', signed=True) z = int.from_bytes(bytes(data[2:4]), 'little', signed=True) print(f"X: {x}, Z: {z}") bus.close() ``` ## Performance Characteristics - **Latency**: ~2-5 ms (I2C + processing) - **Throughput**: 100 reads/second (limited by 100 ms GUI update interval) - **Bandwidth**: 4 bytes × 10 Hz = 320 bytes/second - **Jitter**: ±10 ms (non-deterministic on Linux) ## Troubleshooting | Problem | Likely Cause | Solution | |---------|--------------|----------| | I2C not detected | Arduino not running | Upload firmware to Arduino | | Data is zeros | Encoder not moving | Check encoder connections | | Erratic values | Noise on I2C bus | Add pull-up resistors, shorten wires | | Periodic dropouts | I2C collision | Use slower clock speed (100 kHz) | | Position drifts | Encoder misconfiguration | Calibrate scale factor | ## References - [I2C Specification](https://www.i2c-bus.org/) - [Arduino Wire Library](https://www.arduino.cc/en/Reference/Wire) - [Raspberry Pi I2C Setup](https://learn.adafruit.com/adafruit-16-channel-pwm-servo-driver/using-the-adafruit-library)