On-off lamp
This example shows the basics of a state machine, also known by the
more technical term finite state automaton. The idea is that the
program is in a particular state, and certain events will cause
a transition to another state.
In our case, our light is either on or off (the states), and we
will transition between them with a big enough vibration reading.
Here is a state diagram of this:
stateDiagram-v2
direction LR
[*] --> Off
Off --> On : if vibration < 0.80 and ready
On --> Off : if vibration < 0.80 and ready
Note the “and ready” condition. Given how fast the computer is,
when we tap the light, the vibration value will be less than 0.80 for
many cycles of the event loop, and without some care our light will
flash on and off rapidly, and be unpredictable.
Here is the complete code with several comments included.
We’ll break it down below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
| # Import libraries
import time
import neopixel
import adafruit_dotstar
import pulseio
from analogio import AnalogIn
import board
# Set up neopixel light strip
pixpin = board.D0
numpix = 3
pixels = neopixel.NeoPixel(pixpin, numpix, brightness = 0.5, auto_write=True, pixel_order=neopixel.GRBW)
# Built-in RGB light
dotstar = adafruit_dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1)
vibrationPin = AnalogIn(board.A0)
def get_voltage(pin):
return (pin.value * 3.3) / 65536
# A list of all the states, each uniquely numbered
# (not important what the numbers are,
# as long as they're unique)
OFF = 0
ON = 1
# Variable to keep track of which state we're in.
state = OFF
# Flag to keep track of whether we're "ready" or not
ready = True
# Counter to keep track of when the ready flag should be set
readyCounter = 0
# Counter to print vibration value
printCounter = 0
# Event loop
while True:
vibration = get_voltage(vibrationPin)
# Do code matching the current state, whether OFF or ON
if state == OFF:
# ensure light off
pixels.fill((0, 0, 0, 0))
# check for events which cause transition from this state
if vibration < 0.8 and ready:
# do anything we need to exit this state
# change state for next iteration of the loop
state = ON
# do anything we need to enter new state
# Make us not ready, and set the ready counter
ready = False
readyCounter = 100
elif state == ON:
# ensure light on
pixels[0] = (255, 0, 0, 0)
pixels[1] = (0, 255, 0, 0)
pixels[2] = (0, 0, 255, 0)
# check for events
if vibration < 0.8 and ready:
state = OFF
ready = False
readyCounter = 100
# Handle the counters
if readyCounter > 0:
# Decrement the counter
readyCounter -= 1
# If zero, we're "ready"
if readyCounter == 0:
ready = True
if printCounter == 0:
print(state, ready, vibration)
printCounter = (printCounter + 1) % 10
|