Firmware for a 5-DoF robotic arm with gripper, running on an ATmega128L in pure AVR assembly. The arm is driven joint-by-joint from a keyboard (motor select + hold-to-rotate), the gripper is driven independently from an IR remote, and an LCD provides live feedback. Joint motions can be recorded to internal EEPROM and played back, with sequences persisting across power cycles.
For the full design rationale, timing analysis, and module-level documentation, see documentation/MCU2026-G002.pdf.
- ATmega128L (STK300, 4 MHz)
- Keyboard via USB↔RS-232 adapter (USART0, 9600 8N1)
- IR remote (RC5 protocol) on
INT0 - HD44780 16×2 LCD on the external-memory interface
- MCP2515 + TJA1050 CAN module (SPI) — re-crystalled to 16 MHz for 1 Mbps CAN
- 5× brushless joint motors with closed-loop drivers on the CAN bus
- Hobby servo (gripper) on Timer1 hardware PWM
The firmware is organised in three layers on top of a cooperative scheduler:
- Drivers (
assembly_src/drivers/, plusLibraries_128L-4MHz/lcd.asmandeeprom.asm) — hardware-facing primitives: UART RX ring buffer, RC5 decoder, MCP2515 over SPI, servo PWM, LCD, EEPROM. Each driver hides its peripheral behind a small API. - Applications (
assembly_src/applications/) — own the system's logical state:input_handler— single source of truth for keybindings; translates raw UART/IR events into application calls.arm_controller— owns active motor + per-joint angles; the control-tick ISR advances the held joint and stages CAN frames, which the main loop drains so blocking SPI never runs in interrupt context.gripper_controller— owns the gripper angle; drives the servo on IR digit presses.display_manager— owns the LCD; steady-state view of active motor and angle, with a transientGripper:label on IR events.motion_recorder— record/playback state machine over EEPROM (3-byte frames +0xFFend marker); ISR-side capture + flagging, main-loop EEPROM and CAN work.
- Scheduler (
main.asm) — vector table, init sequence, and the cooperative main loop polling ISR flags.
The system is interrupt-driven with a cooperative main loop: ISRs (Timer3 control tick, USART0 RX, IR + Timer0 bit-sampling) stay short and only touch SRAM; all blocking I/O (CAN over SPI, EEPROM writes, LCD refresh) runs from the main loop.
assembly_src/
├── main.asm entry point, vector table, scheduler
├── definitions.asm shared constants and register aliases
├── macros.asm project-wide macros
├── drivers/ hardware-facing primitives
│ ├── uart_driver.asm
│ ├── ir_5rc_driver.asm
│ ├── can_motor_driver.asm
│ └── servo_driver.asm
├── applications/ logical state and behaviour
│ ├── input_hanlder.asm
│ ├── arm_controller.asm
│ ├── gripper_controller.asm
│ ├── display_manager.asm
│ └── motion_recorder.asm
└── Libraries_128L-4MHz/ course-provided libraries (math, LCD, EEPROM, …)
Report/ full technical report (PDF + demo video)
readme/ README assets
| Input | Action |
|---|---|
Keys 0–4 |
Select arm motor |
W / S (hold) |
Rotate active joint forward / backward |
R / E |
Start / stop recording |
P / X |
Start / stop playback |
IR digits 0–9 |
Set gripper angle in 10° steps (0°–90°) |
The project is a single-unit AVR assembly build — assemble assembly_src/main.asm (which .includes everything else) with AVR Studio 4 / Atmel Studio, then flash the resulting .hex to an ATmega128L clocked at 4 MHz. The MCP2515 module must be re-crystalled to 16 MHz to reach the 1 Mbps CAN bit rate used by the motor drivers.
