156 lines
5.5 KiB
Markdown
156 lines
5.5 KiB
Markdown
# Arduino Stepper Motor Controller
|
|
|
|
A state-machine based Arduino sketch for controlling a 28BYJ-48 stepper motor via Serial communication. The system supports both **Manual** and **Automatic** modes, allowing for relative angle movement, speed control, and configurable wait intervals.
|
|
|
|
## Hardware Requirements
|
|
- **Microcontroller**: Arduino Uno / Mega / Nano
|
|
- **Motor Driver**: ULN2003 (or compatible)
|
|
- **Stepper Motor**: 28BYJ-48 (or compatible bipolar/unipolar stepper)
|
|
|
|
### Pin Connections
|
|
| Pin | Function | Arduino Pin |
|
|
|-----|----------|-------------|
|
|
| IN1 | Step 1 | 9 |
|
|
| IN2 | Step 2 | 10 |
|
|
| IN3 | Step 3 | 11 |
|
|
| IN4 | Step 4 | 12 |
|
|
|
|
## System Configuration
|
|
|
|
### Constants
|
|
- **STEPS_PER_REVOLUTION**: `2048` (Standard for 28BYJ-48 with gear reduction)
|
|
- **DEGREES_PER_STEP**: Calculated as `360.0 / 2048` (~0.1758°)
|
|
|
|
### Global Variables
|
|
| Variable | Type | Description |
|
|
|----------|------|-------------|
|
|
| `autoMode` | `enum` | `AUTO` or `MANUAL` |
|
|
| `targetAngle` | `float` | Target angle in degrees (relative to current position) |
|
|
| `turnSpeed` | `float` | Speed in degrees per second |
|
|
| `_currState` | `enum` | `MOVE` or `WAIT` |
|
|
| `waitInterval` | `float` | Time in seconds to wait in `WAIT` state (only active in AUTO mode) |
|
|
| `_waitTime` | `unsigned long` | Timestamp of when WAIT state began |
|
|
| `_stepInterval` | `float` | Time in seconds between individual steps |
|
|
| `_stepTime` | `unsigned long` | Timestamp of the last step |
|
|
| `_stepCount` | `int` | Total steps to move for the current target |
|
|
| `_stepsRemaining` | `int` | Steps remaining in the current move sequence |
|
|
| `_directionCW` | `bool` | `true` for Clockwise, `false` for Counter-Clockwise |
|
|
|
|
## Serial Command Interface
|
|
|
|
The controller listens to the Serial port (9600 baud). Commands must start with a letter followed by a value. No spaces are required.
|
|
|
|
| Command | Format | Description |
|
|
|---------|--------|-------------|
|
|
| **Mode Switch** | `m0` / `m1` | `m0`: Set to **AUTO** (cycles MOVE/WAIT).<br>`m1`: Set to **MANUAL** (moves once, then waits indefinitely). |
|
|
| **Move Angle** | `a<degrees>` | Move `<degrees>` degrees relative to current position. Supports negative values for reverse direction.<br>*Example*: `a90` (move 90° CW), `a-45` (move 45° CCW). |
|
|
| **Set Speed** | `s<speed>` | Set speed in degrees per second.<br>*Example*: `s10` (10 deg/s). |
|
|
| **Set Wait Time** | `i<seconds>` | Set the duration (in seconds) to wait in `WAIT` state when in AUTO mode.<br>*Example*: `i5` (wait 5 seconds). |
|
|
|
|
## Operational Logic
|
|
|
|
### State Machine
|
|
The system operates in two primary states:
|
|
|
|
1. **MOVE**:
|
|
- The motor steps at the calculated `_stepInterval`.
|
|
- `_stepsRemaining` decrements with each step.
|
|
- When `_stepsRemaining` hits 0, the system transitions to **WAIT**.
|
|
|
|
2. **WAIT**:
|
|
- The motor stops.
|
|
- `_waitTime` is recorded.
|
|
- **In AUTO Mode**: If `millis() - _waitTime > waitInterval`, the system transitions back to **MOVE** (repeats cycle).
|
|
- **In MANUAL Mode**: The system stays in **WAIT** indefinitely until a new Serial command is received.
|
|
|
|
```cpp
|
|
autoMode // AUTO or MANUAL. If AUTO, cycles between MOVE and WAIT state. If MANUAL, goes into MOVE state, but stays in WAIT indefinitely until a new command is sent
|
|
targetAngle // The target angle in degrees, relative to the current position
|
|
turnSpeed // The turn speed in degrees per second
|
|
|
|
_currState // MOVE or WAIT
|
|
|
|
waitInterval // Time to stay in wait state in AUTO mode, in seconds
|
|
_waitTime // Variable to compare against millis()
|
|
|
|
_stepInterval // Time between motor steps, in seconds
|
|
_stepTime // Variable to compare against millis()
|
|
|
|
_stepCount // Number of steps remaining
|
|
_stepRemaining //
|
|
|
|
LOOP
|
|
|
|
--- READ SERIAL ---
|
|
if serial.Available
|
|
|
|
string = serial.readString
|
|
|
|
switch(string[0])
|
|
|
|
case 'm':
|
|
if autoMode != string[1]
|
|
autoMode = AUTO if string[1] == 0, MANUAL if string[1] == 1
|
|
// Start moving following existing parameters, relative to current position
|
|
_currState = MOVE
|
|
_waitTime = 0
|
|
_stepTime = millis()
|
|
_stepsRemaining = _stepCount
|
|
|
|
case 'a':
|
|
// Move this many degrees relative to current position
|
|
targetAngle = strToFloat(string[1:])
|
|
// TODO: Recalculate step count
|
|
_currState = MOVE
|
|
_waitTime = 0
|
|
_stepTime = millis()
|
|
_stepsRemaining = _stepCount
|
|
|
|
case 's':
|
|
// Sets the step interval
|
|
turnSpeed = strToFloat(string[1:])
|
|
// TODO: Recalculate step interval
|
|
|
|
case 'i':
|
|
// Sets the wait interval
|
|
waitInterval = strToFloat(string[1:])
|
|
|
|
|
|
--- Execution Logic ---
|
|
|
|
if _stepsRemaining == 0
|
|
_currState = WAIT
|
|
_waitTime = millis()
|
|
|
|
if autoMode = AUTO and _currState == WAIT and millis() - _waitTime > waitInterval
|
|
_currState = MOVE
|
|
_stepsRemaining = _stepCount
|
|
_stepTime = millis()
|
|
|
|
if currState == MOVE
|
|
if millis() - _stepTime > _stepInterval
|
|
RunStep
|
|
_stepTime = millis()
|
|
_stepsRemaining -= 1
|
|
```
|
|
|
|
### Initialization
|
|
- **Default Mode**: `AUTO`
|
|
- **Default State**: `MOVE`
|
|
- **Default Wait Interval**: `8.0` seconds
|
|
- **Default Speed**: `5.0` degrees/second
|
|
|
|
## Step Sequence Logic
|
|
|
|
The controller supports bidirectional movement by using two sequences:
|
|
- **Clockwise (CW)**: Standard 4-step sequence.
|
|
- **Counter-Clockwise (CCW)**: Reverse of the CW sequence.
|
|
|
|
The direction is determined by the sign of the `targetAngle` when the `a` command is received.
|
|
|
|
## Usage Examples
|
|
|
|
1. **Move 90 degrees clockwise at 10 deg/s**:
|
|
```text
|
|
s10
|
|
a90 |