rpi-io 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +2 -2
- package/documentation/api.md +1 -2
- package/documentation/stepper-motor.md +192 -0
- package/esm/log.mjs +30 -40
- package/extensions/stepper-bipolar.mjs +131 -0
- package/extensions/stepper-unipolar.mjs +172 -0
- package/package.json +6 -2
- package/test/log-warn.js +41 -0
- package/test/stepper-motor-bipolar.js +36 -0
- package/test/stepper-motor-unipolar.js +24 -0
- package/esm/step.mjs +0 -212
- package/test/step-motor.js +0 -59
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
|
+
|
|
3
|
+
## [3.1.0] - 2026-07-22
|
|
4
|
+
### Changed
|
|
5
|
+
- log utility refactored
|
|
6
|
+
### Added
|
|
7
|
+
- extension classes for unipolar and bipolar stepper motors
|
|
8
|
+
|
|
2
9
|
## [3.0.0] - 2026-07-18
|
|
3
10
|
### Added
|
|
4
11
|
- methods **pulseStart**(*count, edge, options*) and **pulseStop**() for output lines
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# rpi-io
|
|
2
2
|
    
|
|
3
3
|
|
|
4
|
-
Current version is 3.
|
|
4
|
+
Current version is 3.1.0. This version takes advantage of the *pulseStart()* and *pulseStop()* methods introduced in version 3.0.0 to propose extension classes for stepper motor control. See [extension](https://github.com/gdorbes/rpi-io/tree/master/extensions) and [documentation](https://github.com/gdorbes/rpi-io/tree/master/documentation) folders.
|
|
5
5
|
|
|
6
6
|
**rpi-io** is a lite [ESM](https://nodejs.org/api/esm.html#modules-ecmascript-modules) module for **Node.js** to control **Raspberry Pi** GPIO: access (in, out), input event detection and [PWM](https://en.wikipedia.org/wiki/Pulse-width_modulation) peripheral control.
|
|
7
7
|
|
|
@@ -169,7 +169,7 @@ setTimeout(()=>{
|
|
|
169
169
|
}, 5000)
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
Pulse sequence
|
|
172
|
+
##### Pulse sequence
|
|
173
173
|
|
|
174
174
|
```js
|
|
175
175
|
import {RIO} from "rpi-io"
|
package/documentation/api.md
CHANGED
|
@@ -114,7 +114,7 @@ myOutput.pulseStart(10, "asc", {
|
|
|
114
114
|
```javascript
|
|
115
115
|
{
|
|
116
116
|
pulseWidth: 10, // pulse width in µs
|
|
117
|
-
spaceWidth: 10 // space
|
|
117
|
+
spaceWidth: 10 // space between pulses in µs
|
|
118
118
|
}
|
|
119
119
|
```
|
|
120
120
|
|
|
@@ -321,7 +321,6 @@ log("This is useful info")
|
|
|
321
321
|
```
|
|
322
322
|
|
|
323
323
|
|
|
324
|
-
|
|
325
324
|
### sleep(time)
|
|
326
325
|
|
|
327
326
|
Similar to `setTimeout` but in async mode.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Stepper Motor Extensions
|
|
2
|
+
|
|
3
|
+
Using the basic **rpi-io** methods for output lines (*write*, *pulseStart*, *pulseStop*), it is easy to drive stepper motors, ranging from simple hobbyist motors (e.g., 28BYJ-48) to those designed for robotics and industrial applications, such as the NEMA series (e.g., NEMA 17, 23...) using some hardware driver (e.g. DMA542).
|
|
4
|
+
|
|
5
|
+
To facilitate this type of use, since version 3.1 **rpi-io** has included two stepper motor controller classes:
|
|
6
|
+
|
|
7
|
+
- The *StepperUnipolar* class is intended for stepper motors without a hardware driver.
|
|
8
|
+
- The *StepperBipolar* class is intended for stepper motors with a hardware driver such as the DM542.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## class StepperUnipolar
|
|
13
|
+
|
|
14
|
+
### Electronic wiring example
|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+
PLEASE NOTE:
|
|
19
|
+
|
|
20
|
+
- **GND is shared** — the Pi's GND and the ULN2003's GND must be tied together even if you power the motor from a separate supply, or the signals won't have a common reference.
|
|
21
|
+
|
|
22
|
+
- **Power source for VCC**: for light loads the Pi's 5V pin can drive the ULN2003/motor directly, but the 28BYJ-48 can draw enough current that it's safer to power VCC from a separate 5V supply, keeping only GND common with the Pi.
|
|
23
|
+
|
|
24
|
+
- The four GPIO pins (17, 18, 27, 22) are just a common convention — any four free GPIO pins work, as long as your code (e.g. via `RPi.GPIO` or `gpiozero`) references the pins you actually wired.
|
|
25
|
+
|
|
26
|
+
- The ULN2003 board's output side connects to the motor with its keyed 5-pin connector — it only fits one way, so no wiring decisions needed there.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Example
|
|
31
|
+
|
|
32
|
+
See test [script](https://github.com/gdorbes/rpi-io/blob/master/test/stepper-motor-unipolar.js).
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import {StepperUnipolar, RIO, traceCfg, log, warn, sleep} from "../extensions/stepper-unipolar.mjs"
|
|
36
|
+
|
|
37
|
+
traceCfg(2)
|
|
38
|
+
|
|
39
|
+
// Open step controller in half step mode => Half turn forward and backward => Close
|
|
40
|
+
const motor28BYJH = new StepperUnipolar(new RIO(21, "output"), new RIO(22, "output"), new RIO(24, "output"), new RIO(25, "output"), "half", 0)
|
|
41
|
+
log("motor28BYJH creation status:", motor28BYJH.status)
|
|
42
|
+
await motor28BYJH.rotate(2048, "forward", false)
|
|
43
|
+
await motor28BYJH.rotate(2048, "backward", false)
|
|
44
|
+
motor28BYJH.close()
|
|
45
|
+
|
|
46
|
+
// Open step controller in full step mode => Half turn forward and backward => Close
|
|
47
|
+
const motor28BYJF = new StepperUnipolar(new RIO(21, "output"), new RIO(22, "output"), new RIO(24, "output"), new RIO(25, "output"), "full", 4)
|
|
48
|
+
log("motor28BYJF creation status:", motor28BYJF.status)
|
|
49
|
+
await motor28BYJF.rotate(1024, "forward", false)
|
|
50
|
+
await motor28BYJF.rotate(1024, "backward", false)
|
|
51
|
+
motor28BYJF.close()
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### API
|
|
57
|
+
|
|
58
|
+
#### constructor StepperUnipolar(coilA, coilB, coilC, coilD, mode, delay)
|
|
59
|
+
|
|
60
|
+
**Parameter(s)**
|
|
61
|
+
|
|
62
|
+
- **coilA** *{Object}* **rpi-io** instance for Coil A
|
|
63
|
+
|
|
64
|
+
- **coilB** *{Object}* **rpi-io** instance for Coil B
|
|
65
|
+
|
|
66
|
+
- **coilC** *{Object}* **rpi-io** instance for Coil C
|
|
67
|
+
|
|
68
|
+
- **coilD** *{Object}* **rpi-io** instance for Coil D
|
|
69
|
+
|
|
70
|
+
- ##### **mode** *{'half','full'}* sequence mode: half step or full step
|
|
71
|
+
|
|
72
|
+
- **delay** *{Number}* delay in ms between steps
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
**Return** *{Object}* StepperUnipolar instance
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
#### rotate(steps, direction, showStep)
|
|
81
|
+
|
|
82
|
+
**Parameter(s)**
|
|
83
|
+
|
|
84
|
+
- **steps** *{Number}*
|
|
85
|
+
- **direction** *{'forward'|'backward"'*
|
|
86
|
+
- **showStep** *{Boolean}* ** to display step in console (default = false)
|
|
87
|
+
|
|
88
|
+
**Return** *{Promise}*
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
#### close()
|
|
93
|
+
|
|
94
|
+
To disable coils and close rpi-io instances.
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## class StepperBipolar
|
|
99
|
+
|
|
100
|
+
### Electronic wiring example
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
PLEASE NOTE:
|
|
105
|
+
|
|
106
|
+
- **The junction dot** is where the Pi's 5V pin splits into two wires, tying PUL+ and DIR+ together onto one common rail.
|
|
107
|
+
|
|
108
|
+
- **STEP and DIR switch low to trigger**, since GPIO pulls PUL- or DIR- down relative to the shared +5V.
|
|
109
|
+
|
|
110
|
+
- **Voltage margin is tight**: the Pi's GPIO output high is 3.3V, but the common rail here is 5V, giving only ~1.7V across the optocoupler when "off" — close to some optocouplers' turn-off threshold. Many builds get away with this, but if you see erratic stepping consider using a Darlington array (e.g. ULN2003) between RPi and DM542.
|
|
111
|
+
|
|
112
|
+
- **ENA+/ENA-** would follow the same common-anode pattern if you wire it — tied into the same 5V junction, with a GPIO pin driving ENA- low to enable.
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
### Example
|
|
117
|
+
|
|
118
|
+
See test [script](https://github.com/gdorbes/rpi-io/blob/master/test/stepper-motor-bipolar.js).
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
import {StepperBipolar, RIO, traceCfg, log, warn, sleep, ctrlC} from "../extensions/stepper-bipolar.mjs"
|
|
122
|
+
|
|
123
|
+
traceCfg(2)
|
|
124
|
+
|
|
125
|
+
ctrlC(() => {
|
|
126
|
+
RIO.closeAll()
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Open output lines GPIO21 and GPIO22
|
|
130
|
+
const pul = new RIO(21, "output", {value: 0})
|
|
131
|
+
const dir = new RIO(22, "output", {value: 0})
|
|
132
|
+
|
|
133
|
+
// Create Bipolar Stepper Motor instance
|
|
134
|
+
const bipolar = new StepperBipolar(pul, dir, "desc", 10)
|
|
135
|
+
|
|
136
|
+
// Start rotating full turn (depending on hardware driver settings)
|
|
137
|
+
bipolar.rotate(25600, "forward").then(stepped => {
|
|
138
|
+
log("stepped:", stepped)
|
|
139
|
+
// Reset and close lines
|
|
140
|
+
pul.write(0)
|
|
141
|
+
dir.write(0)
|
|
142
|
+
pul.close()
|
|
143
|
+
dir.close()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// Stop rotation after 200ms
|
|
147
|
+
await sleep(200)
|
|
148
|
+
log("stop rotation")
|
|
149
|
+
bipolar.stop()
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### API
|
|
155
|
+
|
|
156
|
+
#### constructor StepperBipolar(pul, dir, edge, width)
|
|
157
|
+
|
|
158
|
+
**Parameter(s)**
|
|
159
|
+
|
|
160
|
+
- **pul** *{Object}* **rpi-io** instance for pulse pin
|
|
161
|
+
|
|
162
|
+
- **dir** *{Object}* **rpi-io** instance for direction pin
|
|
163
|
+
|
|
164
|
+
- ##### **edge** *{'desc','asc'}* pulse active edge: descending or ascending
|
|
165
|
+
|
|
166
|
+
- **width** *{Number}* pulse width and space between two edges in µs
|
|
167
|
+
|
|
168
|
+
**Return** *{Object}* StepperBipolar instance
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
#### rotate(steps, direction)
|
|
173
|
+
|
|
174
|
+
**Parameter(s)**
|
|
175
|
+
|
|
176
|
+
- **steps** *{Number}*
|
|
177
|
+
- **direction** *{'forward'|'backward"'*
|
|
178
|
+
- **showStep** *{Boolean}* ** to display step in console (default = false)
|
|
179
|
+
|
|
180
|
+
**Return** *{Promise<{elapsedMs: number, pulsesCompleted: number, stopped: boolean}>}*
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
#### stop()
|
|
185
|
+
|
|
186
|
+
To interrupt an ongoing pulse sequence if one is in progress.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
#### close()
|
|
191
|
+
|
|
192
|
+
To disable *pul* and *dir* rpi-io instances.
|
package/esm/log.mjs
CHANGED
|
@@ -1,58 +1,48 @@
|
|
|
1
1
|
// -------------------------------------------------------------------
|
|
2
2
|
// RPI-IO: Custom console.log
|
|
3
3
|
// -------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
trace: false,
|
|
6
|
-
warn: true
|
|
4
|
+
const noop = function () {
|
|
7
5
|
}
|
|
8
|
-
|
|
6
|
+
export let log = noop
|
|
7
|
+
export let warn = noop
|
|
9
8
|
/** ------------------------------------------------------------------
|
|
10
9
|
* @function traceCfg
|
|
11
10
|
* @description Set log configuration
|
|
12
11
|
* @param {Number} level 0: no log, 1: warn only, 2: warn and log
|
|
13
12
|
*/
|
|
14
13
|
export const traceCfg = level => {
|
|
15
|
-
debug = {
|
|
16
|
-
trace: false,
|
|
17
|
-
warn: false
|
|
18
|
-
}
|
|
19
|
-
level > 1 ? debug.trace = true : false
|
|
20
|
-
level > 0 ? debug.warn = true : false
|
|
21
|
-
}
|
|
22
14
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
minimumFractionDigits: 0,
|
|
33
|
-
useGrouping: false
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** ------------------------------------------------------------------
|
|
38
|
-
* @function log
|
|
39
|
-
* @description Global customized timestamped console.log
|
|
40
|
-
* Requires global variable 'debug'
|
|
41
|
-
*/
|
|
42
|
-
export const log = function () {
|
|
43
|
-
if (debug.trace)
|
|
15
|
+
const nowStr = () => {
|
|
16
|
+
const date = new Date()
|
|
17
|
+
return date.toLocaleTimeString() + "." + date.getMilliseconds().toLocaleString('en', {
|
|
18
|
+
minimumIntegerDigits: 3,
|
|
19
|
+
minimumFractionDigits: 0,
|
|
20
|
+
useGrouping: false
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
const timeStamped = function () {
|
|
44
24
|
console.log.apply(console, Array.prototype.concat.apply([nowStr(), "🔎 "], arguments))
|
|
45
|
-
}
|
|
25
|
+
}
|
|
26
|
+
const timeColored = function () {
|
|
27
|
+
console.log.apply(console, Array.prototype.concat.apply([nowStr(), "⚠️ ", "\x1b[38;2;255;80;0m", ...arguments, "\x1b[0m"]))
|
|
28
|
+
}
|
|
46
29
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
30
|
+
switch (level) {
|
|
31
|
+
case 2:
|
|
32
|
+
warn = timeColored
|
|
33
|
+
log = timeStamped
|
|
34
|
+
break
|
|
35
|
+
case 1:
|
|
36
|
+
warn = timeColored
|
|
37
|
+
log = noop
|
|
38
|
+
break
|
|
39
|
+
default:
|
|
40
|
+
warn = noop
|
|
41
|
+
log = noop
|
|
42
|
+
}
|
|
54
43
|
}
|
|
55
44
|
|
|
45
|
+
|
|
56
46
|
// -------------------------------------------------------------------
|
|
57
47
|
// EoF
|
|
58
48
|
// -------------------------------------------------------------------
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// RPI-IO: BIPOLAR STEPPER MOTOR EXTENSION
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {RIO, traceCfg, log, warn, sleep, ctrlC} from "../esm/main.mjs"
|
|
5
|
+
|
|
6
|
+
export {RIO, traceCfg, log, warn, sleep, ctrlC}
|
|
7
|
+
|
|
8
|
+
/** ------------------------------------------------------------------
|
|
9
|
+
* @class StepperBipolar
|
|
10
|
+
* @description Class definition for Bipolar Stepper motors.
|
|
11
|
+
* Bipolar stepper motors (e.g. NEMA 17 or 23) require hardware driver
|
|
12
|
+
* such as DM542 or equilavent depending on motor power
|
|
13
|
+
*/
|
|
14
|
+
export class StepperBipolar {
|
|
15
|
+
|
|
16
|
+
static STATUS_MSG = {
|
|
17
|
+
0: "none",
|
|
18
|
+
11: "pul or dir rpi-io instance definition is missing",
|
|
19
|
+
12: "At least one rpi-io instance is not valid",
|
|
20
|
+
13: "Wrong edge {'asc','desc'}",
|
|
21
|
+
14: "Wrong pulse width (5 ≤ p ≤ 10,000,000)",
|
|
22
|
+
200: "ok"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static EDGES = ["desc", "asc"]
|
|
26
|
+
|
|
27
|
+
// Private method: Update instance status
|
|
28
|
+
#setStatus(code, data) {
|
|
29
|
+
this.status.code = code
|
|
30
|
+
this.status.msg = StepperBipolar.STATUS_MSG[code]
|
|
31
|
+
this.status.data = data
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** ------------------------------------------------------------------
|
|
35
|
+
* @method constructor
|
|
36
|
+
* @param {Object} pul // rpi-io output instance for pulse pin
|
|
37
|
+
* @param {Object} dir // rpi-io output instance for direction pin
|
|
38
|
+
* @param {"desc"|"asc"} edge // pulse active edge: descending or ascending
|
|
39
|
+
* @param {Number} width // pulse width and space between two edges in µs
|
|
40
|
+
*/
|
|
41
|
+
constructor(pul, dir, edge, width) {
|
|
42
|
+
|
|
43
|
+
// Init instance construction status
|
|
44
|
+
this.status = {
|
|
45
|
+
code: 0,
|
|
46
|
+
msg: StepperBipolar.STATUS_MSG[0],
|
|
47
|
+
data: ""
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ERR11: pul or pir rpi-io instance definition is missing
|
|
51
|
+
if (typeof pul === "undefined" || typeof dir === "undefined") {
|
|
52
|
+
this.#setStatus(11, "")
|
|
53
|
+
RIO.closeAll()
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ERR12: At least one coil port rpi-io instance is not valid
|
|
58
|
+
try {
|
|
59
|
+
pul.write(0)
|
|
60
|
+
dir.write(0)
|
|
61
|
+
} catch (err) {
|
|
62
|
+
this.#setStatus(12, "")
|
|
63
|
+
RIO.closeAll()
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ERR13: Wrong edge {'asc','desc'}
|
|
68
|
+
if (StepperBipolar.EDGES.indexOf(edge) === -1) {
|
|
69
|
+
this.#setStatus(13, edge)
|
|
70
|
+
RIO.closeAll()
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ERR14: Wrong pulse width (5 ≤ p ≤ 10,000,000)
|
|
75
|
+
if (typeof width !== "number" || width < 5 || width > 10000000) {
|
|
76
|
+
this.#setStatus(14, width)
|
|
77
|
+
RIO.closeAll()
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Test successfully completed => Init properties
|
|
82
|
+
this.ioPulse = pul
|
|
83
|
+
this.ioDir = dir
|
|
84
|
+
this.edge = edge
|
|
85
|
+
this.width = width
|
|
86
|
+
this.#setStatus(200, "")
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** ------------------------------------------------------------------
|
|
90
|
+
* @method rotate
|
|
91
|
+
* @description Rotate the motor a certain number of steps forward or backward.
|
|
92
|
+
* Full rotation depends on hardware driver settings.
|
|
93
|
+
* @param {Number} steps
|
|
94
|
+
* @param {"forward"|"backward"} direction
|
|
95
|
+
* @return {Promise<{elapsedMs: number, pulsesCompleted: number, stopped: boolean}>}
|
|
96
|
+
*/
|
|
97
|
+
async rotate(steps, direction) {
|
|
98
|
+
|
|
99
|
+
// Set direction
|
|
100
|
+
this.ioDir.write("forward" ? 1 : 0)
|
|
101
|
+
|
|
102
|
+
// Start rotation
|
|
103
|
+
log("starting rotation:", steps, "steps", direction)
|
|
104
|
+
return await this.ioPulse.pulseStart(steps, this.edge, {
|
|
105
|
+
pulseWidth: this.width,
|
|
106
|
+
spaceWidth: this.width,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** ------------------------------------------------------------------
|
|
111
|
+
* @method stop
|
|
112
|
+
* @description Immediately interrupts an ongoing pulse sequence if one is in progress.
|
|
113
|
+
*/
|
|
114
|
+
stop() {
|
|
115
|
+
this.ioPulse.pulseStop()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** ------------------------------------------------------------------
|
|
119
|
+
* @method close
|
|
120
|
+
* @description Disable pul and dir rpi-io instances used for this step motor controller
|
|
121
|
+
*/
|
|
122
|
+
close() {
|
|
123
|
+
this.ioPulse.close
|
|
124
|
+
this.ioDir.close
|
|
125
|
+
log("Bipolar controller closed")
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// -------------------------------------------------------------------
|
|
130
|
+
// EoF
|
|
131
|
+
// -------------------------------------------------------------------
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// RPI-IO: UNIPOLAR STEPPER MOTOR EXTENSION
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {RIO, traceCfg, log, warn, sleep} from "../esm/main.mjs"
|
|
5
|
+
|
|
6
|
+
export {RIO, traceCfg, log, warn, sleep}
|
|
7
|
+
|
|
8
|
+
/** ------------------------------------------------------------------
|
|
9
|
+
* @class StepperUnipolar
|
|
10
|
+
* @description Class definition for Unipolar Stepper motors.
|
|
11
|
+
* Unipolar stepper motors (e.g. 28BYJ-48) are directly controlled by RPi using
|
|
12
|
+
* a Darlington Transistor Array (e.g. ULN2003)
|
|
13
|
+
*/
|
|
14
|
+
export class StepperUnipolar {
|
|
15
|
+
|
|
16
|
+
static STATUS_MSG = {
|
|
17
|
+
0: "none",
|
|
18
|
+
11: "At least one coil port rpi-io instance definition is missing",
|
|
19
|
+
12: "At least one coil port rpi-io instance is not valid",
|
|
20
|
+
13: "Wrong delay parameter value (0 ≤ d ≤ 1000)",
|
|
21
|
+
14: "Wrong Unipolar sequence {'full','half'}",
|
|
22
|
+
200: "ok"
|
|
23
|
+
}
|
|
24
|
+
static MODE = ["half", "full"]
|
|
25
|
+
static STEPS = {
|
|
26
|
+
half: [
|
|
27
|
+
[1, 0, 0, 0],
|
|
28
|
+
[1, 1, 0, 0],
|
|
29
|
+
[0, 1, 0, 0],
|
|
30
|
+
[0, 1, 1, 0],
|
|
31
|
+
[0, 0, 1, 0],
|
|
32
|
+
[0, 0, 1, 1],
|
|
33
|
+
[0, 0, 0, 1],
|
|
34
|
+
[1, 0, 0, 1]
|
|
35
|
+
],
|
|
36
|
+
full: [
|
|
37
|
+
[1, 0, 0, 1],
|
|
38
|
+
[1, 1, 0, 0],
|
|
39
|
+
[0, 1, 1, 0],
|
|
40
|
+
[0, 0, 1, 1]
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Private method: Update instance status
|
|
45
|
+
#setStatus(code, data) {
|
|
46
|
+
this.status.code = code
|
|
47
|
+
this.status.msg = StepperUnipolar.STATUS_MSG[code]
|
|
48
|
+
this.status.data = data
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** ------------------------------------------------------------------
|
|
52
|
+
* @method constructor
|
|
53
|
+
* @param {Object} coilA // rpi-io output instance for CoilA
|
|
54
|
+
* @param {Object} coilB // rpi-io output instance for CoilB
|
|
55
|
+
* @param {Object} coilC // rpi-io output instance for CoilC
|
|
56
|
+
* @param {Object} coilD // rpi-io output instance for CoilD
|
|
57
|
+
* @param {"half"|"ful"} mode // Full or half step sequence
|
|
58
|
+
* @param {Number} delay // Delay between steps in ms
|
|
59
|
+
*/
|
|
60
|
+
constructor(coilA, coilB, coilC, coilD, mode = "half", delay = 10) {
|
|
61
|
+
|
|
62
|
+
// Init instance construction status
|
|
63
|
+
this.status = {
|
|
64
|
+
code: 0,
|
|
65
|
+
msg: StepperUnipolar.STATUS_MSG[0],
|
|
66
|
+
data: ""
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ERR11: At least one coil port rpi-io instance definition is missing
|
|
70
|
+
if (typeof coilA === "undefined" || typeof coilB === "undefined" || typeof coilC === "undefined" || typeof coilD === "undefined") {
|
|
71
|
+
this.#setStatus(11, "")
|
|
72
|
+
RIO.closeAll()
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ERR12: At least one coil port rpi-io instance is not valid
|
|
77
|
+
try {
|
|
78
|
+
coilA.write(0)
|
|
79
|
+
coilB.write(0)
|
|
80
|
+
coilC.write(0)
|
|
81
|
+
coilD.write(0)
|
|
82
|
+
} catch (err) {
|
|
83
|
+
this.#setStatus(12, "")
|
|
84
|
+
RIO.closeAll()
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ERR13: Wrong delay parameter value (0 ≤ d ≤ 1000)
|
|
89
|
+
if (typeof delay !== "number" || delay < 0 || delay > 1000) {
|
|
90
|
+
this.#setStatus(13, delay)
|
|
91
|
+
RIO.closeAll()
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ERR14: Wrong mode {'full','half'}
|
|
96
|
+
if (StepperUnipolar.MODE.indexOf(mode) === -1) {
|
|
97
|
+
this.#setStatus(14, mode)
|
|
98
|
+
RIO.closeAll()
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Test successfully completed => Init properties
|
|
103
|
+
this.coils = {
|
|
104
|
+
a: coilA,
|
|
105
|
+
b: coilB,
|
|
106
|
+
c: coilC,
|
|
107
|
+
d: coilD,
|
|
108
|
+
}
|
|
109
|
+
this.sequence = StepperUnipolar.STEPS[mode]
|
|
110
|
+
this.len = this.sequence.length
|
|
111
|
+
this.delay = delay
|
|
112
|
+
this.index = 0
|
|
113
|
+
this.increment = 0
|
|
114
|
+
this.#setStatus(200, "")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** ------------------------------------------------------------------
|
|
118
|
+
* @method rotate
|
|
119
|
+
* @description Rotate the motor a certain number of steps forward or backward.
|
|
120
|
+
* Full rotation depends on selected mode.
|
|
121
|
+
* @param {Number} steps
|
|
122
|
+
* @param {"forward"|"backward"} direction
|
|
123
|
+
* @param {Boolean} showStep
|
|
124
|
+
*/
|
|
125
|
+
async rotate(steps, direction, showStep = false) {
|
|
126
|
+
|
|
127
|
+
this.increment = direction === "forward" ? 1 : -1
|
|
128
|
+
|
|
129
|
+
log("starting rotation:", steps, "steps", direction)
|
|
130
|
+
|
|
131
|
+
// Rotate
|
|
132
|
+
for (let i = 0; i < steps; i++) {
|
|
133
|
+
const [a, b, c, d] = this.sequence[this.index]
|
|
134
|
+
if (showStep) {
|
|
135
|
+
log("rotation step:", i, [a, b, c, d])
|
|
136
|
+
}
|
|
137
|
+
this.coils.a.write(a)
|
|
138
|
+
this.coils.b.write(b)
|
|
139
|
+
this.coils.c.write(c)
|
|
140
|
+
this.coils.d.write(d)
|
|
141
|
+
|
|
142
|
+
this.index = ((this.index + this.increment % this.len + this.len) % this.len)
|
|
143
|
+
await sleep(this.delay, false)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Disable coils
|
|
147
|
+
this.coils.a.write(0)
|
|
148
|
+
this.coils.b.write(0)
|
|
149
|
+
this.coils.c.write(0)
|
|
150
|
+
this.coils.d.write(0)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** ------------------------------------------------------------------
|
|
154
|
+
* @method close
|
|
155
|
+
* @description Disable coils and close rpi-io instances used for this step motor controller
|
|
156
|
+
*/
|
|
157
|
+
close() {
|
|
158
|
+
this.coils.a.write(0)
|
|
159
|
+
this.coils.b.write(0)
|
|
160
|
+
this.coils.c.write(0)
|
|
161
|
+
this.coils.d.write(0)
|
|
162
|
+
this.coils.a.close()
|
|
163
|
+
this.coils.b.close()
|
|
164
|
+
this.coils.c.close()
|
|
165
|
+
this.coils.d.close()
|
|
166
|
+
log("Unipolar controller closed")
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// -------------------------------------------------------------------
|
|
171
|
+
// EoF
|
|
172
|
+
// -------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rpi-io",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Nodejs module to control Raspberry Pi GPIO",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"raspberry",
|
|
@@ -18,7 +18,11 @@
|
|
|
18
18
|
"bookworm",
|
|
19
19
|
"trixie",
|
|
20
20
|
"iot",
|
|
21
|
-
"embedded"
|
|
21
|
+
"embedded",
|
|
22
|
+
"motor",
|
|
23
|
+
"stepper",
|
|
24
|
+
"motor control",
|
|
25
|
+
"stepper motor"
|
|
22
26
|
],
|
|
23
27
|
"homepage": "https://github.com/gdorbes/rpi-io#readme",
|
|
24
28
|
"bugs": {
|
package/test/log-warn.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// TEST CUSTOM CONSOLE
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {traceCfg, log, warn} from "../esm/log.mjs"
|
|
5
|
+
|
|
6
|
+
// Default behavior: No console
|
|
7
|
+
log("nothing")
|
|
8
|
+
warn("nothing")
|
|
9
|
+
|
|
10
|
+
// Full console
|
|
11
|
+
traceCfg(2)
|
|
12
|
+
log("console display")
|
|
13
|
+
warn("warning display")
|
|
14
|
+
|
|
15
|
+
// Warning only
|
|
16
|
+
traceCfg(1)
|
|
17
|
+
log("not displayed")
|
|
18
|
+
warn("warning display again")
|
|
19
|
+
|
|
20
|
+
// Back to no console
|
|
21
|
+
traceCfg(0)
|
|
22
|
+
log("nothing again")
|
|
23
|
+
warn("nothing again")
|
|
24
|
+
|
|
25
|
+
// Full console
|
|
26
|
+
traceCfg(2)
|
|
27
|
+
log("console display again")
|
|
28
|
+
warn("warning display again")
|
|
29
|
+
|
|
30
|
+
// Warning only
|
|
31
|
+
traceCfg(1)
|
|
32
|
+
log("not displayed")
|
|
33
|
+
warn("warning display again again")
|
|
34
|
+
|
|
35
|
+
// Back to no console
|
|
36
|
+
traceCfg(0)
|
|
37
|
+
log("nothing again")
|
|
38
|
+
warn("nothing again")
|
|
39
|
+
// -------------------------------------------------------------------
|
|
40
|
+
// EoF
|
|
41
|
+
// -------------------------------------------------------------------
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// RPI-IO: BIPOLAR STEPPER MOTOR TEST - DM542 HARDWARE DRIVER
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {StepperBipolar, RIO, traceCfg, log, warn, sleep, ctrlC} from "../extensions/stepper-bipolar.mjs"
|
|
5
|
+
|
|
6
|
+
traceCfg(2)
|
|
7
|
+
|
|
8
|
+
ctrlC(() => {
|
|
9
|
+
RIO.closeAll()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
// Open output lines GPIO21 and GPIO22
|
|
13
|
+
const pul = new RIO(21, "output", {value: 0})
|
|
14
|
+
const dir = new RIO(22, "output", {value: 0})
|
|
15
|
+
|
|
16
|
+
// Create Bipolar Stepper Motor instance
|
|
17
|
+
const bipolar = new StepperBipolar(pul, dir, "desc", 10)
|
|
18
|
+
|
|
19
|
+
// Start rotating full turn (depending on hardware driver settings)
|
|
20
|
+
bipolar.rotate(25600, "forward").then(stepped => {
|
|
21
|
+
log("stepped:", stepped)
|
|
22
|
+
// Reset and close lines
|
|
23
|
+
pul.write(0)
|
|
24
|
+
dir.write(0)
|
|
25
|
+
pul.close()
|
|
26
|
+
dir.close()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// Stop rotation after 200ms
|
|
30
|
+
await sleep(200)
|
|
31
|
+
log("stop rotation")
|
|
32
|
+
bipolar.stop()
|
|
33
|
+
|
|
34
|
+
// -------------------------------------------------------------------
|
|
35
|
+
// EoF
|
|
36
|
+
// -------------------------------------------------------------------
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// RPI-IO: UNIPOLAR STEPPER MOTOR TEST
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {StepperUnipolar, RIO, traceCfg, log, warn, sleep} from "../extensions/stepper-unipolar.mjs"
|
|
5
|
+
|
|
6
|
+
traceCfg(2)
|
|
7
|
+
|
|
8
|
+
// Open step controller in half step mode => Half turn forward and backward => Close
|
|
9
|
+
const motor28BYJH = new StepperUnipolar(new RIO(21, "output"), new RIO(22, "output"), new RIO(24, "output"), new RIO(25, "output"), "half", 0)
|
|
10
|
+
log("motor28BYJH creation status:", motor28BYJH.status)
|
|
11
|
+
await motor28BYJH.rotate(2048, "forward", false)
|
|
12
|
+
await motor28BYJH.rotate(2048, "backward", false)
|
|
13
|
+
motor28BYJH.close()
|
|
14
|
+
|
|
15
|
+
// Open step controller in full step mode => Half turn forward and backward => Close
|
|
16
|
+
const motor28BYJF = new StepperUnipolar(new RIO(21, "output"), new RIO(22, "output"), new RIO(24, "output"), new RIO(25, "output"), "full", 4)
|
|
17
|
+
log("motor28BYJF creation status:", motor28BYJF.status)
|
|
18
|
+
await motor28BYJF.rotate(1024, "forward", false)
|
|
19
|
+
await motor28BYJF.rotate(1024, "backward", false)
|
|
20
|
+
motor28BYJF.close()
|
|
21
|
+
|
|
22
|
+
// -------------------------------------------------------------------
|
|
23
|
+
// EoF
|
|
24
|
+
// -------------------------------------------------------------------
|
package/esm/step.mjs
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
// -------------------------------------------------------------------
|
|
2
|
-
// RPI-IO: STEP MOTOR EXTENSION ⚠️ Work in Progress
|
|
3
|
-
// -------------------------------------------------------------------
|
|
4
|
-
import {RIO} from "./main.mjs";
|
|
5
|
-
// -------------------------------------------------------------------
|
|
6
|
-
// UTILITY FUNCTIONS
|
|
7
|
-
/** ------------------------------------------------------------------
|
|
8
|
-
* @function tlog
|
|
9
|
-
* @description Timestamped console.log
|
|
10
|
-
*/
|
|
11
|
-
export function tlog() {
|
|
12
|
-
const date = new Date()
|
|
13
|
-
const nowMs = date.toLocaleTimeString() + "." + date.getMilliseconds().toLocaleString('en', {
|
|
14
|
-
minimumIntegerDigits: 3,
|
|
15
|
-
minimumFractionDigits: 0,
|
|
16
|
-
useGrouping: false
|
|
17
|
-
})
|
|
18
|
-
console.log.apply(console, Array.prototype.concat.apply([nowMs, "🔎 "], arguments))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** ------------------------------------------------------------------
|
|
22
|
-
* @function wait
|
|
23
|
-
* @description Wait ms as a promise and optional tlog
|
|
24
|
-
* @param {Number} ms
|
|
25
|
-
* @param {Boolean} logWait
|
|
26
|
-
*/
|
|
27
|
-
export function wait(ms, logWait = true) {
|
|
28
|
-
logWait ? tlog("sleeping", ms, "ms") : false
|
|
29
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export class STEP {
|
|
33
|
-
|
|
34
|
-
static STATUS_MSG = {
|
|
35
|
-
0: "none",
|
|
36
|
-
1: "Unknown driver name",
|
|
37
|
-
11: "At least one coil port rpi-io instance definition is missing",
|
|
38
|
-
12: "At least one coil port rpi-io instance is not valid",
|
|
39
|
-
13: "Wrong delay parameter value (0 ≤ d ≤ 1000)",
|
|
40
|
-
14: "Wrong ULN2003 sequence {'full','half'}",
|
|
41
|
-
200: "ok"
|
|
42
|
-
}
|
|
43
|
-
static ULN2003_MODE = ["half", "full"]
|
|
44
|
-
static ULN2003_STEPS = {
|
|
45
|
-
half: [
|
|
46
|
-
[1, 0, 0, 0],
|
|
47
|
-
[1, 1, 0, 0],
|
|
48
|
-
[0, 1, 0, 0],
|
|
49
|
-
[0, 1, 1, 0],
|
|
50
|
-
[0, 0, 1, 0],
|
|
51
|
-
[0, 0, 1, 1],
|
|
52
|
-
[0, 0, 0, 1],
|
|
53
|
-
[1, 0, 0, 1]
|
|
54
|
-
],
|
|
55
|
-
full: [
|
|
56
|
-
[1, 0, 0, 1],
|
|
57
|
-
[1, 1, 0, 0],
|
|
58
|
-
[0, 1, 1, 0],
|
|
59
|
-
[0, 0, 1, 1]
|
|
60
|
-
]
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Private method: Update instance status
|
|
64
|
-
#setStatus(code, data) {
|
|
65
|
-
this.status.code = code
|
|
66
|
-
this.status.msg = STEP.STATUS_MSG[code]
|
|
67
|
-
this.status.data = data
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** ------------------------------------------------------------------
|
|
71
|
-
* @method constructor
|
|
72
|
-
* @param {String} driver // Supported driver name
|
|
73
|
-
* @param {Object} rios // rpi-io Instance container depending on driver
|
|
74
|
-
* @param {Object} opt // Options depending on driver
|
|
75
|
-
*/
|
|
76
|
-
constructor(driver, rios, opt) {
|
|
77
|
-
|
|
78
|
-
const defopt = {
|
|
79
|
-
// Parameters for ULN2003
|
|
80
|
-
delay: 10,
|
|
81
|
-
sequence: "half"
|
|
82
|
-
}
|
|
83
|
-
opt = {...defopt, ...opt}
|
|
84
|
-
|
|
85
|
-
// Init instance construction status
|
|
86
|
-
this.status = {
|
|
87
|
-
code: 0,
|
|
88
|
-
msg: STEP.STATUS_MSG[0],
|
|
89
|
-
data: ""
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Test parameters depending on driver
|
|
93
|
-
switch (driver) {
|
|
94
|
-
case "uln2003":
|
|
95
|
-
|
|
96
|
-
// ERR11: At least one coil port rpi-io instance definition is missing
|
|
97
|
-
if (typeof rios.coilA === "undefined" || typeof rios.coilB === "undefined" || typeof rios.coilC === "undefined" || typeof rios.coilD === "undefined") {
|
|
98
|
-
this.#setStatus(11, "")
|
|
99
|
-
RIO.closeAll()
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ERR12: At least one coil port rpi-io instance is not valid
|
|
104
|
-
try {
|
|
105
|
-
rios.coilA.write(0)
|
|
106
|
-
rios.coilB.write(0)
|
|
107
|
-
rios.coilC.write(0)
|
|
108
|
-
rios.coilD.write(0)
|
|
109
|
-
} catch (err) {
|
|
110
|
-
this.#setStatus(12, "")
|
|
111
|
-
RIO.closeAll()
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ERR13: Wrong delay parameter value (0 ≤ d ≤ 1000)
|
|
116
|
-
if (typeof opt.delay !== "number" || opt.delay < 0 || opt.delay > 1000) {
|
|
117
|
-
this.#setStatus(13, opt.delay)
|
|
118
|
-
RIO.closeAll()
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ERR14: Wrong ULN2003 sequence {'full','half'}
|
|
123
|
-
if (STEP.ULN2003_MODE.indexOf(opt.sequence) === -1) {
|
|
124
|
-
this.#setStatus(14, opt.sequence)
|
|
125
|
-
RIO.closeAll()
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Test successfully completed => Init properties
|
|
130
|
-
this.driver = "uln2003"
|
|
131
|
-
this.props = {
|
|
132
|
-
a: rios.coilA,
|
|
133
|
-
b: rios.coilB,
|
|
134
|
-
c: rios.coilC,
|
|
135
|
-
d: rios.coilD,
|
|
136
|
-
sequence: STEP.ULN2003_STEPS[opt.sequence],
|
|
137
|
-
len: STEP.ULN2003_STEPS[opt.sequence].length,
|
|
138
|
-
delay: opt.delay,
|
|
139
|
-
inc: 0,
|
|
140
|
-
index: 0
|
|
141
|
-
}
|
|
142
|
-
this.#setStatus(200, "")
|
|
143
|
-
break
|
|
144
|
-
default:
|
|
145
|
-
this.#setStatus(1, driver)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/** ------------------------------------------------------------------
|
|
150
|
-
* @method rotate
|
|
151
|
-
* @description Rotate the motor a certain number of steps forward or backward.
|
|
152
|
-
* A full rotation consists of 200 steps.
|
|
153
|
-
* @param {Number} steps
|
|
154
|
-
* @param {"forward"|"backward"} direction
|
|
155
|
-
* @param {Boolean} showStep
|
|
156
|
-
*/
|
|
157
|
-
async rotate(steps, direction, showStep = false) {
|
|
158
|
-
|
|
159
|
-
switch (this.driver) {
|
|
160
|
-
case "uln2003":
|
|
161
|
-
this.props.inc = direction === "forward" ? 1 : -1
|
|
162
|
-
|
|
163
|
-
tlog("starting rotation:", steps, "steps", direction)
|
|
164
|
-
|
|
165
|
-
// Rotate
|
|
166
|
-
for (let i = 0; i < steps; i++) {
|
|
167
|
-
const [a, b, c, d] = this.props.sequence[this.props.index]
|
|
168
|
-
if (showStep) {
|
|
169
|
-
tlog("rotation step:", i, [a, b, c, d])
|
|
170
|
-
}
|
|
171
|
-
this.props.a.write(a)
|
|
172
|
-
this.props.b.write(b)
|
|
173
|
-
this.props.c.write(c)
|
|
174
|
-
this.props.d.write(d)
|
|
175
|
-
|
|
176
|
-
this.props.index = ((this.props.index + this.props.inc) % this.props.len + this.props.len) % this.props.len
|
|
177
|
-
await wait(this.props.delay, false)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Disable coils
|
|
181
|
-
this.props.a.write(0)
|
|
182
|
-
this.props.b.write(0)
|
|
183
|
-
this.props.c.write(0)
|
|
184
|
-
this.props.d.write(0)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/** ------------------------------------------------------------------
|
|
189
|
-
* @method close
|
|
190
|
-
* @description Disable coils and close rpi-io instances used for step motor controller
|
|
191
|
-
*/
|
|
192
|
-
close() {
|
|
193
|
-
|
|
194
|
-
switch (this.driver) {
|
|
195
|
-
case "uln2003":
|
|
196
|
-
this.props.a.write(0)
|
|
197
|
-
this.props.b.write(0)
|
|
198
|
-
this.props.c.write(0)
|
|
199
|
-
this.props.d.write(0)
|
|
200
|
-
this.props.a.close()
|
|
201
|
-
this.props.b.close()
|
|
202
|
-
this.props.c.close()
|
|
203
|
-
this.props.d.close()
|
|
204
|
-
tlog("ULN2003 controller closed")
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
// -------------------------------------------------------------------
|
|
211
|
-
// EoF
|
|
212
|
-
// -------------------------------------------------------------------
|
package/test/step-motor.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// -------------------------------------------------------------------
|
|
2
|
-
// RPI-IO: STEP MOTOR TEST SCRIPT ⚠️ Work in Progress
|
|
3
|
-
// -------------------------------------------------------------------
|
|
4
|
-
import {RIO} from "../esm/main.mjs";
|
|
5
|
-
import {STEP, tlog} from "../esm/step.mjs"
|
|
6
|
-
|
|
7
|
-
// Close any open rpi-io instance to prevent error
|
|
8
|
-
RIO.closeAll()
|
|
9
|
-
|
|
10
|
-
// Open step controller in half step mode => Half turn forward and backward => Close
|
|
11
|
-
const motor28BYJH = new STEP("uln2003", {
|
|
12
|
-
coilA: new RIO(21, "output"),
|
|
13
|
-
coilB: new RIO(22, "output"),
|
|
14
|
-
coilC: new RIO(24, "output"),
|
|
15
|
-
coilD: new RIO(25, "output")
|
|
16
|
-
}, {
|
|
17
|
-
delay: 0,
|
|
18
|
-
sequence: "half"
|
|
19
|
-
})
|
|
20
|
-
tlog("motor28BYJH creation status:", motor28BYJH.status)
|
|
21
|
-
await motor28BYJH.rotate(2048, "forward", false)
|
|
22
|
-
await motor28BYJH.rotate(2048, "backward", false)
|
|
23
|
-
motor28BYJH.close()
|
|
24
|
-
|
|
25
|
-
// Open step controller in full step mode => Half turn forward and backward => Close
|
|
26
|
-
const motor28BYJF = new STEP("uln2003", {
|
|
27
|
-
coilA: new RIO(21, "output"),
|
|
28
|
-
coilB: new RIO(22, "output"),
|
|
29
|
-
coilC: new RIO(24, "output"),
|
|
30
|
-
coilD: new RIO(25, "output")
|
|
31
|
-
}, {
|
|
32
|
-
delay: 4,
|
|
33
|
-
sequence: "full"
|
|
34
|
-
})
|
|
35
|
-
tlog("motor28BYJF creation status:", motor28BYJF.status)
|
|
36
|
-
await motor28BYJF.rotate(1024, "forward", false)
|
|
37
|
-
await motor28BYJF.rotate(1024, "backward", false)
|
|
38
|
-
motor28BYJF.close()
|
|
39
|
-
|
|
40
|
-
// A4988 drivers require one line per parameter as in the example below
|
|
41
|
-
const a4988 = {
|
|
42
|
-
pulse: new RIO(5, "output"),
|
|
43
|
-
direction: new RIO(6, "output"),
|
|
44
|
-
enable: new RIO(26, "output")
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// DM452 drivers require one line per parameter as in the example below
|
|
48
|
-
const dm452 = {
|
|
49
|
-
pulse: new RIO(16, "output"),
|
|
50
|
-
direction: new RIO(17, "output"),
|
|
51
|
-
polarity: new RIO(27, "output")
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// When done close all rpi-io instances
|
|
55
|
-
RIO.closeAll()
|
|
56
|
-
|
|
57
|
-
// -------------------------------------------------------------------
|
|
58
|
-
// EoF
|
|
59
|
-
// -------------------------------------------------------------------
|