rpi-io 2.2.4 → 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 +14 -3
- package/README.md +21 -4
- package/addon/gpio.c +435 -4
- package/documentation/api.md +67 -1
- package/documentation/examples.md +3 -0
- package/documentation/stepper-motor.md +192 -0
- package/esm/log.mjs +30 -40
- package/esm/main.mjs +56 -3
- 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/pulse.js +43 -0
- package/test/read.js +2 -0
- package/test/stepper-motor-bipolar.js +36 -0
- package/test/stepper-motor-unipolar.js +24 -0
- package/test/write.js +1 -0
- package/esm/uln2003.mjs +0 -115
- package/test/exampleUln2003.js +0 -103
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
|
+
// -------------------------------------------------------------------
|
package/test/pulse.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// -------------------------------------------------------------------
|
|
2
|
+
// TEST - Simple slow and fast pulse trains
|
|
3
|
+
// -------------------------------------------------------------------
|
|
4
|
+
import {RIO, traceCfg, log, sleep, ctrlC, lineNumber} from "../esm/main.mjs"
|
|
5
|
+
|
|
6
|
+
(async () => {
|
|
7
|
+
traceCfg(2)
|
|
8
|
+
|
|
9
|
+
// Read line number from command line
|
|
10
|
+
const line = lineNumber(2)
|
|
11
|
+
if (line < 0) return
|
|
12
|
+
|
|
13
|
+
// Init output line and ctrl+c to close it
|
|
14
|
+
const led = new RIO(line, "output", {value: 0})
|
|
15
|
+
log("led:", led)
|
|
16
|
+
ctrlC(() => {
|
|
17
|
+
led.close()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// Slow pulse x10, ascending edge, w = 0.5 s, s = 0.5 s
|
|
21
|
+
const pulseStatus = await led.pulseStart(10, "asc", {
|
|
22
|
+
pulseWidth: 500000,
|
|
23
|
+
spaceWidth: 500000
|
|
24
|
+
})
|
|
25
|
+
log("pulse status stopped when completed:", pulseStatus)
|
|
26
|
+
|
|
27
|
+
// Fast pulse x1000, descending edge, w = 5µs, s = 5µs
|
|
28
|
+
led.write(1) // Init line according to edge
|
|
29
|
+
led.pulseStart(1000, "desc", {
|
|
30
|
+
pulseWidth: 5,
|
|
31
|
+
spaceWidth: 5
|
|
32
|
+
}).then(pulseStatus => {
|
|
33
|
+
log("pulse status stopped when stopped:", pulseStatus)
|
|
34
|
+
led.write(0) // Reset line
|
|
35
|
+
led.close()
|
|
36
|
+
})
|
|
37
|
+
await sleep(5)
|
|
38
|
+
led.pulseStop() // Stop pulse train after 5ms
|
|
39
|
+
|
|
40
|
+
})()
|
|
41
|
+
// -------------------------------------------------------------------
|
|
42
|
+
// EoF
|
|
43
|
+
// -------------------------------------------------------------------
|
package/test/read.js
CHANGED
|
@@ -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/test/write.js
CHANGED
package/esm/uln2003.mjs
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
// -------------------------------------------------------------------
|
|
2
|
-
// RPI-IO: ULN2003 STEP MOTORS CONTROL
|
|
3
|
-
// -------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
import {RIO} from "./main.mjs";
|
|
6
|
-
|
|
7
|
-
export class ULN2003 {
|
|
8
|
-
|
|
9
|
-
static RPi_GPIO_STD = [5, 6, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27]
|
|
10
|
-
static RPi_GPIO_PWM = [12, 13, 18, 19]
|
|
11
|
-
|
|
12
|
-
/** ------------------------------------------------------------------
|
|
13
|
-
* @function isValidGpio
|
|
14
|
-
* @description Check if pin a valid multipurpose GPIO
|
|
15
|
-
* @param {Number} pin
|
|
16
|
-
* @return {Boolean}
|
|
17
|
-
*/
|
|
18
|
-
static static isValidGpio(pin) {
|
|
19
|
-
return [...ULN2003.RPi_GPIO_STD, ...ULN2003.RPi_GPIO_PWM].GPIOS.includes(pin);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
static MODE = ["half", "full"]
|
|
23
|
-
static STEPS = {
|
|
24
|
-
half: [
|
|
25
|
-
[1, 0, 0, 0],
|
|
26
|
-
[1, 1, 0, 0],
|
|
27
|
-
[0, 1, 0, 0],
|
|
28
|
-
[0, 1, 1, 0],
|
|
29
|
-
[0, 0, 1, 0],
|
|
30
|
-
[0, 0, 1, 1],
|
|
31
|
-
[0, 0, 0, 1],
|
|
32
|
-
[1, 0, 0, 1]
|
|
33
|
-
],
|
|
34
|
-
full: [
|
|
35
|
-
[1, 0, 0, 1],
|
|
36
|
-
[1, 1, 0, 0],
|
|
37
|
-
[0, 1, 1, 0],
|
|
38
|
-
[0, 0, 1, 1]
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
/** ------------------------------------------------------------------
|
|
44
|
-
* @method constructor
|
|
45
|
-
* @param {Array} pins - Array of 4 GPIO BCM port number e.g. [21,22,24,25]
|
|
46
|
-
* @param {Object} opt - Delay between steps and sequencing mode. See below
|
|
47
|
-
*/
|
|
48
|
-
constructor(pins, opt) {
|
|
49
|
-
|
|
50
|
-
// Init options with default values and check validity
|
|
51
|
-
const defopt = {
|
|
52
|
-
// Delay between two steps in 1 ≤ ms ≤ 1000
|
|
53
|
-
delayMs: 10,
|
|
54
|
-
// Sequencing mode: 'full' or 'half' (default)
|
|
55
|
-
seqMode: ULN2003.MODE[0]
|
|
56
|
-
}
|
|
57
|
-
opt = {...defopt, ...opt}
|
|
58
|
-
opt.seqMode = opt.seqMode.toLowerCase()
|
|
59
|
-
|
|
60
|
-
// Check if pins
|
|
61
|
-
pins.forEach(pin => {
|
|
62
|
-
if (!ULN2003.isValidGpio(pin)) {
|
|
63
|
-
throw new Error("Invalid pin number: " + pin)
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
rpiIoInstances.forEach(instance => {
|
|
69
|
-
if (!instance instanceof RIO) throw new Error("Invalid instance")
|
|
70
|
-
if (instance.mode !== "output") throw new Error("Invalid instance mode")
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
// Reset option values if not valid
|
|
74
|
-
if (ULN2003.MODE.indexOf(opt.seqMode) === -1) opt.seqMode = defopt.seqMode
|
|
75
|
-
if (typeof opt.delayMs !== "number" || opt.delayMs < 1 || opt.delayMs > 1000) opt.delayMs = defopt.delayMs
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Throw error if list of rpi-io instances is not valid: wrong number, wrong instance, wrong mode
|
|
79
|
-
if (!Array.isArray(rpiIoInstances) || rpiIoInstances.length !== 4) throw new Error("Invalid instance list.")
|
|
80
|
-
rpiIoInstances.forEach(instance => {
|
|
81
|
-
if (!instance instanceof RIO) throw new Error("Invalid instance")
|
|
82
|
-
if (instance.mode !== "output") throw new Error("Invalid instance mode")
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
// No option error here
|
|
86
|
-
|
|
87
|
-
this.coils = rpiIoInstances
|
|
88
|
-
this.sequence = ULN2003.STEPS[opt.seqMode]
|
|
89
|
-
this.len = this.sequence.length
|
|
90
|
-
this.delay = opt.delayMs
|
|
91
|
-
this.A = rpiIoInstances[0]
|
|
92
|
-
this.B = rpiIoInstances[1]
|
|
93
|
-
this.C = rpiIoInstances[2]
|
|
94
|
-
this.D = rpiIoInstances[0]
|
|
95
|
-
this.inc = 0
|
|
96
|
-
this.index = 0
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const toto = new ULN2003()
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
/** ------------------------------------------------------------------
|
|
104
|
-
* @method uln2003
|
|
105
|
-
* @description To control step motors based on ULN20003-like drivers.
|
|
106
|
-
* This function used 4 rpi-io output instances to control
|
|
107
|
-
* step motors back and forth.
|
|
108
|
-
* @param {Object} pins
|
|
109
|
-
* @param {Number} steps - Nombre de pas (entier > 0)
|
|
110
|
-
* @param {'fwd'|'rev'} dir - Direction : 'fwd' = avant, 'rev' = arrière
|
|
111
|
-
*/
|
|
112
|
-
|
|
113
|
-
// -------------------------------------------------------------------
|
|
114
|
-
// EoF
|
|
115
|
-
// -------------------------------------------------------------------
|
package/test/exampleUln2003.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// -------------------------------------------------------------------
|
|
2
|
-
// TEST - ULN 2003
|
|
3
|
-
// -------------------------------------------------------------------
|
|
4
|
-
import {RIO, traceCfg, log, sleep, ctrlC, lineNumber} from "../esm/main.mjs"
|
|
5
|
-
|
|
6
|
-
(async () => {
|
|
7
|
-
traceCfg(2)
|
|
8
|
-
|
|
9
|
-
// Init outputs
|
|
10
|
-
const pins = {
|
|
11
|
-
A: new RIO(21, 'output', {value: 0}),
|
|
12
|
-
B: new RIO(22, 'output', {value: 0}),
|
|
13
|
-
C: new RIO(24, 'output', {value: 0}),
|
|
14
|
-
D: new RIO(25, 'output', {value: 0}),
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const HALF_STEP = [
|
|
18
|
-
[1, 0, 0, 0],
|
|
19
|
-
[1, 1, 0, 0],
|
|
20
|
-
[0, 1, 0, 0],
|
|
21
|
-
[0, 1, 1, 0],
|
|
22
|
-
[0, 0, 1, 0],
|
|
23
|
-
[0, 0, 1, 1],
|
|
24
|
-
[0, 0, 0, 1],
|
|
25
|
-
[1, 0, 0, 1],
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
const FULL_STEP = [
|
|
29
|
-
[1, 0, 0, 1],
|
|
30
|
-
[1, 1, 0, 0],
|
|
31
|
-
[0, 1, 1, 0],
|
|
32
|
-
[0, 0, 1, 1],
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
/** ------------------------------------------------------------------
|
|
36
|
-
* @function write
|
|
37
|
-
* @param {Number} port
|
|
38
|
-
* @param {Number} value
|
|
39
|
-
*/
|
|
40
|
-
const write = (port, value) => {
|
|
41
|
-
pins[port].write(value)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const reset = () => {
|
|
45
|
-
for (const [port, instance] of Object.entries(pins)) {
|
|
46
|
-
instance.write(0)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const test = async () => {
|
|
51
|
-
for (const [port, instance] of Object.entries(pins)) {
|
|
52
|
-
instance.write(1)
|
|
53
|
-
await sleep(500)
|
|
54
|
-
instance.write(0)
|
|
55
|
-
await sleep(500)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Close ports on ctrl+c
|
|
60
|
-
ctrlC(() => {
|
|
61
|
-
reset()
|
|
62
|
-
RIO.closeAll();
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
/** --------------------------------------------------------------
|
|
66
|
-
* @function stepMotor
|
|
67
|
-
* @param {Object} opts
|
|
68
|
-
* @param {Number} opts.steps - Nombre de pas (entier > 0)
|
|
69
|
-
* @param {'fwd'|'rev'} opts.dir - Direction : 'fwd' = avant, 'rev' = arrière
|
|
70
|
-
* @param {number} opts.delayMs - Délai entre deux pas en millisecondes (≥ 1)
|
|
71
|
-
* @param {'half'|'full'} [opts.mode='half'] - Mode de séquençage
|
|
72
|
-
* @returns {Promise<void>}
|
|
73
|
-
*/
|
|
74
|
-
async function stepMotor({steps, dir = 'fwd', delayMs = 10, mode = 'half'}) {
|
|
75
|
-
const sequence = mode === 'half' ? HALF_STEP : FULL_STEP;
|
|
76
|
-
const len = sequence.length;
|
|
77
|
-
const inc = dir === 'fwd' ? 1 : -1;
|
|
78
|
-
let index = 0;
|
|
79
|
-
|
|
80
|
-
for (let i = 0; i < steps; i++) {
|
|
81
|
-
const [a, b, c, d] = sequence[index];
|
|
82
|
-
write('A', a);
|
|
83
|
-
write('B', b);
|
|
84
|
-
write('C', c);
|
|
85
|
-
write('D', d);
|
|
86
|
-
index = ((index + inc) % len + len) % len;
|
|
87
|
-
await sleep(delayMs); // sleep() natif rpi-io
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Désactivation des bobines
|
|
91
|
-
write('A', 0);
|
|
92
|
-
write('B', 0);
|
|
93
|
-
write('C', 0);
|
|
94
|
-
write('D', 0);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
await stepMotor({ steps: 1600, dir: 'rev', delayMs: 8 })
|
|
99
|
-
|
|
100
|
-
})()
|
|
101
|
-
// -------------------------------------------------------------------
|
|
102
|
-
// EoF
|
|
103
|
-
// -------------------------------------------------------------------
|