Project 2 — Finite State Machines#
Turn the distance sensor you calibrated at Lesson 22 into the range channel of a fire-control system: implement the SEARCH / DETECT / LOCK engagement state machine on your Arduino Due, with a Moore telemetry output, a Mealy weapon-release output guarded by two interlocks, and the target-loss edges a real sensor forces you to think about.
At a glance
Work days are Lessons 26 and 27; groups of 2. Lesson 26 is Parts 1–4 (wiring,
the diagram, the table, the transitions); Lesson 27 is Parts 5–6 (the outputs and the
demo). Worth 3 project points — one for the demo and code walkthrough, one for the
diagram and table, one for the discussion questions. One group submission to the
Gradescope assignment Project 2, with three files: your sketch (.ino), your completed
transition-table workbook (.xlsx), and one PDF with your diagram, your documentation
statement and both names. The four discussion questions are answered individually, in
their own Gradescope assignment, Project 2 Discussion Questions. Gradescope is
authoritative for both deadlines.
GenAI is authorized up to Level 4 — co-create and revise, as defined in the AW GenAI Policy. That is looser than the Lesson 22 lab, which was Level 3. You are responsible for demonstrating understanding of anything you take from generative AI.
The Scenario#
You are building the engagement logic of a short-range fire-control system, and you are building it out of the parts on your bench:
On the bench |
In the scenario |
|---|---|
Sharp IR sensor on |
the seeker’s range channel — how far away the target is |
Serial Monitor |
the scope display — one status line per engagement tick |
Your keyboard |
the operator console — lock and pickle (weapon-release consent) commands |
Jumper from pin |
the master arm plug — inserted is ARMED, absent is SAFE |
|
telemetry to the weapons panel — a status voltage another subsystem reads |
|
the launch indicator |
At Lesson 24 you saw safe, searching, locked, engaged listed as an everyday FSM whose transitions are safety-critical. This is a machine of that kind — here arming is an interlock input, not a state. The difference is that this one runs on your board, off a sensor you calibrated yourself, and the transitions are yours to get right.
Educational exercise
This scenario does not represent an actual weapon system, its interlocks, or its release logic.
Start With the Demo#
Open the FSM Explorer and select the Mealy · Fire Control Radar tab:
https://usafa-ece.org/apps/fsm-demo/
This is the machine you are about to build in hardware: the same three states with the same encodings, the same five inputs, the same priority order inside each state, and both target-loss edges. Each bubble shows its state’s telemetry voltage, and FIRE (\(\text{LOCK} \cdot P \cdot E \cdot M\)) belongs on an arrow, not in a bubble.
Out of the box the demo steps the specification itself. Set \(D\), \(E\) and \(M\) with their
checkboxes and press Step to advance one tick. \(L\) and \(P\) are one-shot buttons, and
pressing one while the demo is stopped is a step: one press is one tick with that key in
it, so do not follow it with Step as well. (While the demo is running, the press waits
for the next tick.) The machine moves exactly as your board should. Under the status line,
an event line prints the same *** MISSILE AWAY *** and NO FIRE messages your Serial
Monitor will, the launch indicator strobes on the shot, and on the next step the demo
reacquires the target that is still sitting there.
Use the demo to test your logic, not to copy it
The demo’s transition arcs, their labels, its reference transition table and its Show Answer button sit behind an Instructor reveal that your instructor runs in class. The diagram and the table are one of your three project points, so on your own, use the demo to check the work you have already done:
Predict, then step. Set the inputs, read the next state and FIRE off your own table and diagram, then step the demo and compare. Every disagreement is a row to fix.
Hunt the corners. Lose the target from DETECT and from LOCK. Pickle from outside the envelope, with the master arm safe, and with both. Fire, then step once more.
Check your equations. If you derive next-state and FIRE equations from your table, enter them in the Student Logic card and press Test All Rows. The demo checks them against the machine and lists the input combinations where they disagree, without telling you the right answer.
The two target-loss edges are part of the stated spec, and you are graded on producing a correct diagram and table from it — loss edges included. They must appear on your state diagram, in your transition table, and in your code, and your instructor will ask you to demonstrate both.
The Machine You Will Build#
States and the Moore output#
Three states, encoded in two bits — exactly the situation you set up at Lesson 25 and in the Objective 2.8 reading, and with exactly the same leftover code:
State |
\(Q_1 Q_0\) |
The seeker is… |
Telemetry on |
|---|---|---|---|
SEARCH |
|
scanning; nothing inside the detection gate |
0.8 V |
DETECT |
|
tracking a target, not locked onto it |
1.6 V |
LOCK |
|
holding the target, ready to be committed |
2.4 V |
(illegal) |
|
never entered by design — see the guard below |
— |
The weapons panel reads that voltage to know what the seeker is doing. It depends on the state and on nothing else.
Inputs, read once every 2 s tick#
Signal |
Name |
Where it comes from |
It is 1 when |
|---|---|---|---|
\(D\) |
target detected |
your calibrated |
\(d \leq 12.0\) cm — the detection gate |
\(E\) |
in engagement envelope |
the same distance |
\(d \leq 6.0\) cm — the engagement envelope |
\(M\) |
master arm |
the arming plug on pin |
the plug is inserted (the pin reads LOW) |
\(L\) |
lock command |
|
the key arrived since the last tick |
\(P\) |
pickle — weapon release consent |
|
the key arrived since the last tick |
Three things about that table are worth a second look.
The envelope sits inside the gate. \(6.0 \leq 12.0\), so \(E\) true forces \(D\) true. If your
status line ever shows D=0 E=1, your two thresholds are the wrong way round.
The master arm is fail-safe by construction. INPUT_PULLUP ties the pin HIGH through an
internal resistor, so an empty socket reads HIGH, which we define as SAFE. Inserting the
plug pulls the pin to GND — LOW — which is ARMED. A pulled plug, a broken wire, or a pin
you forgot to configure all read SAFE. The system fails toward not shooting. Wiring it the
other way round (jumper to \(+3.3\) V for ARMED) would mean a disconnected wire arms the
weapon, which is why nothing real is wired that way.
\(L\) and \(P\) are one-shots. Keys you press between ticks sit in the serial receive buffer until the next tick reads them. Each key sets its flag once; both flags are cleared at the end of the tick that consumed them. Holding a key down does not hold the input high.
Transitions — the requirements#
You will produce the transition table yourself. Here is the behavior it must describe.
The order of the checks inside each state is part of the specification — write them as
if / else if in the order given, or the machine will do the wrong thing on the ticks
where two conditions are true at once.
From SEARCH
If \(D\) — go to DETECT.
Otherwise stay in SEARCH.
Nothing else happens in SEARCH. A lock command with no target is not a transition.
From DETECT
If not \(D\) — the target is lost. Go to SEARCH.
Else if \(L\) — go to LOCK.
Else stay in DETECT.
Loss is tested before lock on purpose: you cannot lock onto something you can no longer see.
From LOCK
If not \(D\) — the target is lost. Break lock and go to SEARCH.
Else if \(P\) and \(E\) and \(M\) — a valid weapon release. Assert FIRE, then go to SEARCH: the target has been serviced.
Else if \(L\) — the operator has broken lock manually. Go back to DETECT; the target is still there.
Else stay in LOCK.
A pickle that fails an interlock — \(P\) with \(E\) false, or \(P\) with \(M\) false — is not a transition. The machine stays in LOCK and says why (below).
The illegal state. Two bits hold four codes and you are using three, so 11 exists in
the hardware whether your design uses it or not. The starter sketch provides the guard that
forces any state that is not one of the three legal codes to SEARCH, and you must leave
it in place. It forces SEARCH specifically because SEARCH is the state farthest from a shot
and the only one that claims nothing about a target: a corrupted state must fail safe.
Building your transition table#
Build your table in the template workbook,
ECE215_Project2_TransitionTable_Template.xlsx.
It holds one row per rule, in the shape below. Each input column takes 1 (the input must
be 1), 0 (it must be 0) or x (this row does not care). The first row is done to show the
format; every ? is yours.
# |
Present state |
\(Q_1 Q_0\) |
\(D\) |
\(E\) |
\(M\) |
\(L\) |
\(P\) |
Next state |
\(Q_1^+ Q_0^+\) |
FIRE |
|---|---|---|---|---|---|---|---|---|---|---|
1 |
SEARCH |
|
1 |
x |
x |
x |
x |
DETECT |
|
0 |
2 |
? |
? |
? |
? |
? |
? |
? |
? |
? |
? |
3 |
? |
? |
? |
? |
? |
? |
? |
? |
? |
? |
… |
You decide how many rows LOCK needs; that is the point of the exercise. Every row must have a defined next state, and a state’s rows must together cover every combination of the five inputs, so that no combination leaves the machine without a rule.
Rows are tried top to bottom, and the first match wins, exactly like the if /
else if chain you write in Section 3. Write a row so that it excludes the rows above it
where that is natural: the DETECT lock row carries a 1 under \(D\), not an x, so the row
says on its own that you lock only onto a target you can see. A LOCK row that comes after
the FIRE row does not have to spell out “not (\(P \cdot E \cdot M\))”. It applies only when
the FIRE row did not match, and that is exactly what your code does too.
The autograder reads your workbook the same way. A state and input combination that no row covers is a failure, named by the state and the inputs. A row that can never match, because the rows above it already cover every combination it claims, comes back as a note.
Outputs — one Moore, one Mealy#
This is the distinction Quiz 7 asks you about, and your machine now carries one of each:
Output |
Kind |
Depends on |
Behavior |
|---|---|---|---|
Telemetry voltage on |
? |
? |
0.8 V / 1.6 V / 2.4 V — one per state |
FIRE |
? |
? |
|
Discussion Question 1 asks you to justify these two classifications from the definitions and from your code — fill the table in once you can.
FIRE is asserted only when all four of these hold at the same time: the machine is in LOCK, the operator pressed \(P\), the target is inside the envelope (\(E\)), and the master arm plug is inserted (\(M\)).
A pickle in LOCK that fails an interlock prints a denial and changes nothing (the two checks run in priority order):
in LOCK, with \(P\) and \(D\) and not \(E\) →
NO FIRE -- OUTSIDE ENVELOPEin LOCK, with \(P\) and \(D\) and not \(M\) →
NO FIRE -- MASTER ARM SAFE
The LOCK qualifier is load-bearing. A pickle in DETECT, with a target in front of the sensor, the master arm inserted and the target inside the envelope, was never a candidate for anything: the machine is not locked, so it must print no denial and must not fire. A pickle typed in SEARCH with no target in sight stays silent too, but \(D = 0\) already sees to that; the DETECT case is the one that needs the qualifier. The autograder checks it, with a pickle in DETECT while a target is present and a pickle on the tick a target first appears.
Check the envelope first, then the master arm — so a pickle with both interlocks open reports the envelope. If you prefer the other order, that is fine, but then say so explicitly, and be consistent across your diagram, your table, and your code.
Both denials carry \(D\), and that is not decoration. A denial is a claim about a target that is still there: “outside the envelope” only means something if there is something to be outside it. On the tick a target disappears, \(E\) goes false along with \(D\), the machine breaks lock to SEARCH — and it should say nothing at all, not complain about an envelope it is no longer looking at. The starter hands your output function \(D\) for exactly this.
The status line#
Every tick prints one line — your scope display:
LOCK d= 5.3 cm D=1 E=1 ARM=1
You cannot debug a state machine whose state you cannot see. This line is provided; use it.
Equipment#
Arduino Due and its mini-USB cable (the port labeled USB Programming — the middle of the three connectors on that edge — programs the board)
Sharp GP2Y0A51SK0F distance sensor, wired white→
A0, red→5V, black→GNDOne jumper wire for the master arm plug — pin
2toGNDTwo jumper wires and a digital multimeter for the telemetry output —
DAC1andGNDA flat target you can move by hand, and a ruler
Your calibrated sketch from the Lesson 22 lab — you need
CAL_KandCAL_B
Part 1 — Wire the Two Deltas#
Your sensor wiring from Lesson 22 does not change. Add two things to it.
The master arm plug. One jumper wire from digital pin
2to anyGNDpin. Leave it out of the board to start with.pinMode(2, INPUT_PULLUP)is already in the starter sketch’ssetup().The telemetry tap. Put the DMM’s red probe on
DAC1and its black probe onGND, and set the meter to DC volts.
DAC1, not DAC0, and not an analog input pin
DAC1 is an output. Do not connect the sensor’s white lead, the arming jumper, or
\(+3.3\) V to it. The Due’s pins are not 5 V tolerant, and the same rule that kept the sensor
safe at Lesson 22 applies here.
You should see the DMM read about 0.55 V the moment the sketch starts, before you write anything — that is the DAC’s floor, not zero. More on that below.
Part 2 — Get the Starter Sketch Running#
Open EngagementFSM_Starter.ino. It is
laid out in five labeled sections:
Section |
Whose |
What it holds |
|---|---|---|
0 — CONFIG |
provided |
pins, the 12.0 cm and 6.0 cm thresholds, the 2 s tick, the launch-indicator strobe ( |
1 — PLUG IN |
yours |
|
2 — PLUMBING |
provided, do not modify |
sensor read, serial one-shots, |
3 — TRANSITIONS |
yours |
the |
4 — OUTPUTS |
yours |
the Moore telemetry write and the Mealy FIRE |
Do Section 1 first. Copy CAL_K and CAL_B out of your Lesson 22 sketch and paste your
distanceCm() line back in. Until CAL_K is something other than 0.0 the sketch reports
d= --- cm, \(D\) and \(E\) are always 0, and the machine sits in SEARCH forever no matter
what you type — which looks exactly like broken state logic and is not.
You should see a line every 2 seconds, SEARCH with a real distance in it, and D
flipping to 1 when you bring the target inside 12 cm.
Part 3 — Draw the Diagram, Then Build the Table#
Do this before you write any state logic: the diagram on paper, the table in the workbook.
Draw the state transition diagram. Three bubbles with their
00/01/10encodings and their telemetry voltages inside them, and one arrow for every rule in the requirements above — including both target-loss edges. FIRE is a Mealy output, so it goes on its arrow, not in a bubble.Fill in the transition table in the template workbook, in the shape given above.
Check the two together. Every arrow on the diagram is a row in the table, and every row is an arrow. Walk each state and confirm that its conditions leave no input combination without a rule.
Debugging a table is far cheaper than debugging a program.
Part 4 — Write the Transitions#
Fill in the switch (state) in Section 3, one case at a time, in the priority order the
requirements give. Leave the illegal-state guard at the bottom alone.
Test each state as you go, using the status line and the fact that you control every input:
SEARCH → DETECT: move the target inside 12 cm.
DETECT → SEARCH: take it away again.
DETECT → LOCK: type
'l'.LOCK → SEARCH: take the target away while locked.
LOCK → DETECT: type
'l'again while locked, with the target still there.
You should see the state name in the status line change on the very next tick after the input, and never change on a tick where no input changed.
Part 5 — Write the Outputs#
Fill in Section 4.
The Moore output: call
dacWriteVolts()with 0.8, 1.6, or 2.4 depending on the state, and confirm each one on the DMM.dacWriteVolts()already handles the Due’s real output span for you — see Discussion Question 2 for why that mapping is not the obvious one.The Mealy output: when and only when all four conditions hold, print
*** MISSILE AWAY ***and callflashLaunchIndicator(). That provided helper strobesLED_BUILTIN10 times at 10 Hz (one second) inside the shot tick, and the tick still lasts 2 s. It is one call with noelsebranch: the LED stays dark on every tick that does not fire.The two denials: envelope first, then master arm.
You should see the DMM settle on a new voltage within one tick of every state change, and the LED strobe on the shot tick and stay dark on every other tick.
Part 6 — Rehearse the Demo#
Run the script below end to end at least twice before you call your instructor over. It is the same script you will be graded on, and it takes about a minute at a 2 s tick.
The Demo Script#
Your instructor will ask you to fly this engagement, and both of you should be able to narrate what the machine is doing and why:
Cold start. Nothing in front of the sensor. Status reads
SEARCH, DMM reads 0.8 V, arming plug out.Acquire. Bring the target in to about 10 cm. → DETECT, DMM 1.6 V, status shows
D=1 E=0.Lock. Type
'l'. → LOCK, DMM 2.4 V.Refused pickle — SAFE. With the plug still out, bring the target inside 6 cm so
E=1, then type'p'. →NO FIRE -- MASTER ARM SAFE. Still LOCK, still 2.4 V.Arm. Insert the arming plug. Status shows
ARM=1. Nothing else changes.Refused pickle — outside the envelope. Back the target out to about 10 cm so
E=0, then type'p'. →NO FIRE -- OUTSIDE ENVELOPE. Still LOCK.Close and fire. Bring the target back inside 6 cm and type
'p'. →*** MISSILE AWAY ***, the LED strobes, and the machine returns itself to SEARCH. The DMM follows to 0.8 V on the next tick — the shot tick itself still reads 2.4 V (Moore).Target loss from DETECT. Let the machine reacquire to DETECT, then wave the target away. → SEARCH on the next tick.
Target loss from LOCK. Reacquire, type
'l'to get back to LOCK, then wave the target away. → SEARCH, break lock.
After the shot, the machine reacquires — that is correct
At step 7 the target is still sitting in front of the sensor when the machine returns to SEARCH, so the very next tick sees \(D\) and moves it to DETECT. That is the machine doing exactly what you told it to. Do not “fix” it. Be ready to explain it, because it is a good question for your instructor to ask.
Discussion Questions#
You answer these four individually, in their own Gradescope assignment, Project 2 Discussion Questions, not in your group’s PDF; together they are the third project point. They are printed here in full so you can read them ahead; Gradescope adds the answer choices. Every answer is a multiple-choice pick or a number, and Gradescope grades each one automatically.
1. Moore, Mealy, or both? Your machine carries two outputs: the DAC1 telemetry
voltage and FIRE. Classify each one by the Objective 2.8 test, and check it against
your own Section 4: what does that output function actually need to be told? Each choice
pairs a classification with its justification, so you pick the one where both are right.
1.1 The
DAC1telemetry voltage: Moore or Mealy, and why?1.2 FIRE: Moore or Mealy, and why?
2. What can the DAC actually put out? The Due’s DAC does not reach the rails: its
true output span is \(\tfrac{1}{6}\) to \(\tfrac{5}{6}\) of 3.3 V, or 0.55 V to 2.75 V, and
analogWrite() defaults to 8-bit resolution. The starter’s dacWriteVolts(), provided
in Section 2, is what turns each voltage you ask for into a DAC code.
2.1 Compute the DAC’s step size \(\Delta V\) across that real span, in millivolts per step.
2.2 How many DAC steps separate adjacent telemetry voltages (0.8 V to 1.6 V, and 1.6 V to 2.4 V)?
2.3 Suppose the design had specified 0.0 V / 1.0 V / 3.0 V for SEARCH, DETECT and LOCK instead, and Section 4 passed those three values to
dacWriteVolts(). What would a DMM onDAC1read in the three states?
3. What is one ADC count worth at the detection gate? Use this calibration, not your
own, so that everyone works the same numbers: the sensor’s datasheet fit to the Lesson 22
model \(d = K/V + B\), with CAL_K = 6.20 cm·V and CAL_B = −0.75 cm. The Lesson 22 lab
gave you the Due’s ADC step, \(\Delta V = 3.22\) mV, and the detection gate is
\(d = 12.0\) cm. You can get there either by evaluating \(d = K/V + B\) at \(V\) and again at
\(V + \Delta V\) and subtracting, or by differentiating.
3.1 How many centimeters is one ADC count worth at \(d = 12.0\) cm? Give the size of the step as a positive number.
3.2 The Lesson 22 lab held a calibration to \(|\text{error}| \leq 0.5\) cm on held-out check points. With that much calibration bias allowed, which limits the accuracy of the detection decision more, quantization or calibration bias, and by roughly what factor?
4. Why does the illegal state have to fail to SEARCH? Two bits hold four codes and your
design uses three, so the code 11 exists in the hardware even though your design never
enters it. The starter’s nextState() begins int next = s;, and its switch has a
case only for SEARCH, DETECT and LOCK, and no default; the provided guard at the
bottom then forces any other code to SEARCH. Suppose that guard were deleted and the
machine somehow ended up holding 11.
4.1 What does a
nextState()built this way do once the machine holds11?4.2 Why does the guard force SEARCH, rather than DETECT or LOCK?
Submission Requirements#
This project is worth a total of 3 project points.
(1 Project Point) Demonstrate your FSM and walk through your code with your instructor. Each member of the group should expect to describe a part of the code. Your instructor will decide who is doing which parts of the walkthrough.
(1 Project Point) State transition diagram and corresponding state transition table
(1 Project Point) Answers to the four discussion questions, entered individually in the Gradescope assignment Project 2 Discussion Questions. Gradescope grades the 9 parts automatically; each is worth one ninth of this point, so 6 of 9 earns two thirds of it, and your score is final: there is no correction step on the discussion questions.
Submit to the Gradescope programming assignment Project 2, once per group (add your partner to the submission), with three files:
Your sketch: the
.inofile, as it runs on your boardYour transition table: the completed template workbook (
.xlsx)One PDF containing your state transition diagram, a documentation statement, and both names
(Don’t worry about a specific format for the PDF.)
Gradescope runs an autograder on every submission. It runs your sketch in a simulation of the board and reports on two things: whether your sketch flies the demo script and the edge cases, and whether your table describes the machine and agrees with your code. Read the report, fix what it finds, and resubmit as often as you like until the deadline. It awards no points by itself: your instructor awards the first two project points above and reads the report as evidence; the third comes from the discussion questions.
Then each of you, on your own, answers the four discussion questions in the Gradescope assignment Project 2 Discussion Questions. That assignment is individual, not a group submission, and your answers go there, not in the PDF.
Check Gradescope for the exact deadline of each.
Submission Checklist#
Arming plug wired — jumper from pin
2toGND— and the DMM onDAC1andGNDCAL_KandCAL_Bfrom the Lesson 22 lab plugged in anddistanceCm()completedState transition diagram drawn — three states, both target-loss edges, FIRE on its arrow
Transition table completed — every state against every input condition, in priority order
Transitions written in Section 3, with the illegal-state guard left in place
Moore telemetry verified on the DMM — 0.8 V, 1.6 V, 2.4 V
Mealy FIRE verified —
MISSILE AWAY, the LED strobe, and both refusal messagesBoth target-loss edges demonstrated — one from DETECT and one from LOCK
Full demo script run for your instructor, both partners walking through code
Documentation statement — collaboration, internet resources, and any GenAI use
One PDF: the diagram, the documentation statement, both names
Group submission to Project 2 on Gradescope:
.ino,.xlsx, PDF; autograder report readIndividual submission to Project 2 Discussion Questions on Gradescope
On to Block 3#
You have now built the decision half of a fire-control system: given a range, when does the machine call it a detection, and what is it allowed to do about it. Every one of those decisions rested on a threshold, and every threshold rested on the calibration you fit at Lesson 22.
Block 3 builds the other half — the physics of the detection itself. Where your \(D\) was a comparison against 12.0 cm, a radar’s is a comparison of received signal against noise: the radar range equation, signal-to-noise ratio, and the minimum detectable signal decide whether there is anything to compare at all. And then electronic warfare attacks that comparison directly — a jammer does not flip your \(D\) bit, it raises the noise floor until the seeker cannot honestly set it.
Files#
Starter sketch — EngagementFSM_Starter.ino
Transition-table template — ECE215_Project2_TransitionTable_Template.xlsx
FSM Explorer, Mealy · Fire Control Radar tab — https://usafa-ece.org/apps/fsm-demo/