Home › Practice Tools › Robotics Simulator (Wokwi-style)
๐Ÿค–
Robotics / IoT

Robotics Simulator (Wokwi-style)

A simplified virtual LED/circuit simulator, in the style of an ESP32 blink starter. Write pseudo-code, watch the virtual LED respond. Save and share your projects.
Ideal for: IoT/embedded-systems beginners taking their first steps before touching real hardware.

What you'll practice

Start practicing

Robotics Simulator (Wokwi-style) is part of Practice Tools. Sign in or create an account, then subscribe for โ‚ฆ4,000/month to unlock it.

๐Ÿ“‹ Lab Instructions

Step-by-step exercises for Robotics Simulator (Wokwi-style) - read them here, then practice live in the tool above.

Beginners Robotics Lab

Last updated: August 9, 2026

What you're practicing: real embedded/Arduino-style syntax โ€” pinMode, digitalWrite, and delay โ€” the same three building blocks behind almost every real Wokwi or ESP32 blink starter project, on a virtual LED with no hardware required. This is the expanded version of this lab: more explanation, more patterns to build, and a glossary if any of the terms are new to you.

๐Ÿ”Œ What this simulator actually does

This sandbox is intentionally simple, so read this before you start: it reads your code top to bottom, one line at a time, and only recognises three exact patterns:

  • pinMode(LED, OUTPUT); โ€” sets up the pin (just logs a confirmation)
  • digitalWrite(LED, HIGH); โ€” turns the virtual LED ON
  • digitalWrite(LED, LOW); โ€” turns the virtual LED OFF
  • delay(500); โ€” waits that many milliseconds before the next change happens

There are no loops or conditionals here yet โ€” that's Labs 2 and 3. Right now it's all about one core embedded-programming habit: sequence and timing. Every line must end with a semicolon, and the pin is always written exactly as LED (capital letters), HIGH, and LOW โ€” the simulator is looking for that exact spelling.

๐Ÿ“– Quick glossary โ€” skip this if these are all familiar

  • Pin โ€” a physical connection point on a real circuit board where a component (like an LED) is wired in. Here, it's simplified to one virtual pin called LED.
  • pinMode โ€” the setup step that tells the board "this pin will be used to send power out" (OUTPUT), as opposed to reading a sensor (INPUT).
  • digitalWrite โ€” the command that actually changes a pin's state: HIGH means "send power" (LED on), LOW means "stop sending power" (LED off).
  • delay(ms) โ€” pauses before the next instruction. ms stands for milliseconds โ€” there are 1000 in a second, so delay(1000); is a one-second wait.
  • Semicolon ; โ€” marks the end of an instruction, the same way a period ends a sentence. Real embedded code (and JavaScript) is strict about this.

๐Ÿ› ๏ธ Step-by-step

  1. Click "Open" to launch the simulator. You'll see three panels: your code on the left, a virtual LED and a run log on the right.
  2. Read the starter code already in the editor before changing anything. It should turn the LED on and off twice. Count how many digitalWrite lines it has, out loud or in your head, before running it.
  3. Click โ–ถ Run Simulation. Watch the LED and the log panel together โ€” the log tells you exactly when ("Nms") each change happens.
  4. Checkpoint: does the number of ON/OFF entries in the log match the number of digitalWrite lines you counted in step 2? If not, re-read your code line by line before continuing.
  5. Before you touch the code again: predict what will happen if you double every delay(500) to delay(1000). Write your prediction down somewhere, even just in your head โ€” specifically, predict the new timestamp of the very last log entry.
  6. Make that change, run it again, and check your prediction against what actually happened in the log.
  7. Now try the opposite โ€” change the delays to something short, like delay(100) โ€” and run it. Notice how much faster the blinking reads in the log, and how much smaller the final timestamp is.
  8. Delete everything and write your own sequence from scratch: start with pinMode(LED, OUTPUT);, then alternate digitalWrite(LED, HIGH); / digitalWrite(LED, LOW); with a delay(...) line after each one.
  9. Before running your new sequence, add up your own delay values by hand and predict the final log timestamp โ€” then run it and check.
  10. Intentionally remove one delay(...) line from the middle of your sequence and run it again. Watch what happens to the log timestamps around that spot โ€” this is the fastest way to really understand what delay is doing.
  11. Put the delay(...) line back, and add a comment-style note to yourself in the editor (a line starting with anything not matching the four patterns is simply ignored, so short throwaway notes are safe to leave in).
  12. Once you've built a pattern you're happy with, click Save and give it a title that describes the pattern (not just "My Project").

๐ŸŽฏ Try these patterns โ€” easiest to hardest

  1. Single blink. One HIGH, a delay(500);, one LOW. Confirm you get exactly one log entry for ON and one for OFF.
  2. Fast double-blink. Two quick on/off cycles with a short delay (e.g. 150ms), then a longer pause before repeating the pair once more by copying the lines.
  3. One long, deliberate blink. A single HIGH, a long delay(2000);, then LOW โ€” notice how the log makes the timing obvious even though nothing "moves" on screen for two full seconds.
  4. Uneven rhythm. Alternate short and long delays on purpose (e.g. 200ms, 800ms, 200ms, 800ms) to create a pattern that doesn't feel evenly spaced, like a heartbeat.
  5. Three-beat pattern. Design a sequence with exactly three ON periods of different lengths (e.g. short, medium, long), each followed by the same short pause, and predict the total runtime before you run it.
  6. Your own "signal." Invent a short on/off pattern that could mean something (like a doorbell ring-ring-pause, or a warning flash) and write down in one sentence what it's meant to signal before you build it.

๐Ÿงฎ Reading the log like a pro

Every log line's number is the total elapsed milliseconds since the run started โ€” not the gap since the previous line. If you see 500ms: LED ON followed by 1200ms: LED OFF, the LED was actually on for 1200 โˆ’ 500 = 700ms, even though the delay you wrote right before the OFF line might have said something else entirely โ€” because delay values accumulate across every line before them, not just the one immediately above. Getting comfortable doing that subtraction in your head is exactly the skill that makes reading a real embedded device's timing log easy later.

๐Ÿงฏ Common mistakes

  • Nothing happens when I run it โ€” check every line ends with a semicolon, and that you typed LED, HIGH, and LOW exactly, in capitals.
  • The LED changes instantly instead of waiting โ€” you're missing a delay(...) line between your HIGH and LOW calls; without it, both changes are scheduled at the same moment.
  • My pattern doesn't loop โ€” that's expected right now; this simulator plays your sequence once, start to finish. Looping behaviour is introduced in Lab 2.
  • I get confused reading the log โ€” remember the numbers are total elapsed milliseconds from the start of the run, not the gap since the last line โ€” see the section above.
  • I wrote digitalWrite(led, high) in lowercase and nothing happened โ€” this simulator matches exact capitalisation; real Arduino code is also case-sensitive for these constants, so this habit will serve you later too.
  • My delay seems to apply to the wrong LED change โ€” remember a delay(...) line affects everything that comes after it, not the line directly above it; re-read the "Reading the log like a pro" section if this feels confusing.

โœ… Before you save, check:

  • Every digitalWrite line has a matching delay after it
  • You ran your code at least once after every change, not just once at the end
  • You correctly predicted at least one change before running it, including one full timestamp calculation done by hand
  • You tried removing a delay line on purpose and understood why the timing shifted
  • Your saved title describes the pattern, so you can tell your projects apart later

๐Ÿ’ญ Reflection (a sentence or two, before you save)

Which pattern was hardest to get the timing right on, and what did you change in your thinking to fix it? There's no wrong answer here โ€” this is about noticing your own learning, not getting a perfect score.

๐Ÿ’ก Tip: embedded code is really just "wait, then change something" repeated in sequence. Getting comfortable reading a timeline of on/off/wait โ€” and doing the mental math to know exactly when each change happens โ€” before any real loops or sensors are involved, is exactly what makes the jump to real conditional and repeating logic in Lab 2 much easier.

Intermediate Robotics Lab

Last updated: August 9, 2026

Building on Lab 1: you can already write a sequence of pinMode, digitalWrite, and delay lines and correctly predict when the LED will change, including doing the cumulative-time math by hand. This lab is about two intermediate skills: designing longer, precise, composite patterns, and practicing conditional thinking the way real embedded engineers do before their code ever touches a board.

๐Ÿ” Quick recap โ€” the four patterns this simulator reads

  • pinMode(LED, OUTPUT); ยท digitalWrite(LED, HIGH); ยท digitalWrite(LED, LOW); ยท delay(ms);

Everything else on a line is simply ignored โ€” which is actually useful, and Lab 1 briefly mentioned it: it means you can write a short plain-English note on its own line as a comment-style reminder, and the simulator will skip right over it without breaking anything.

๐Ÿง  An honest note on "conditionals" in this sandbox

Real Arduino/embedded code has genuine if/else logic โ€” "if the sensor reads above X, do this; otherwise do that." This particular simulator does not evaluate real conditions โ€” it only ever plays a flat sequence of lines, in order, every time. So in this lab, "conditional logic" means something specific: you'll write two separate, complete sequences โ€” one for each branch of a scenario โ€” as if you were sketching out both possible paths a real program might take, before ever writing the real if/else that would choose between them. This is a genuine professional habit, not a workaround: experienced embedded developers often draft both branches of a decision as plain sequences first, to make sure each one is correct in isolation, before wiring the actual condition around them.

๐Ÿ› ๏ธ Step-by-step

  1. Open the simulator and clear the starter code.
  2. Plan before you type. On paper or in your head, sketch a short "timing table" for a pattern with at least 4 ON/OFF changes: list each change and the target cumulative timestamp you want it to land on.
  3. Write the code for your planned pattern, using your timing table as the source of truth for each delay(...) value.
  4. Before running, do the cumulative math by hand for your very last line and write down what timestamp you expect the final log entry to show.
  5. Run it. Compare the actual final timestamp in the log to your prediction โ€” if they don't match, find exactly which delay value caused the drift rather than guessing and re-typing randomly.
  6. Hit an exact target. Design a fresh sequence, with at least 3 ON periods, whose total runtime adds up to exactly 6000ms. Use only your own arithmetic โ€” no trial and error โ€” then run it once to confirm.
  7. Build a composite signal: an SOS-style pattern โ€” three short flashes, three long flashes, three short flashes, each group separated by a slightly longer pause than the gaps within a group. Plan the timing table first, same as step 2.
  8. Branch practice: pick a simple two-outcome scenario (e.g. "battery level normal" vs "battery level low, flash a warning"). Write two complete, separate sequences โ€” one per branch โ€” each preceded by a plain-English note line describing which condition it represents. Run each one and confirm it matches its own description.
  9. Compare your two branch sequences side by side. Are they meaningfully different (different pattern, not just different comments)? A believable "low battery" warning should read as urgent โ€” shorter, faster flashes โ€” while "normal" might just be one calm blink.
  10. Debug a broken sequence (see the challenge block below) before writing any more of your own code.
  11. Once your SOS pattern, your exact-6000ms pattern, and your two branch sequences are all working and saved as separate ideas (you can keep them in one project or save them one at a time), pick your favourite and polish it โ€” clean timing, a clear title.
  12. Save your final project with a title describing the pattern and the technique used, e.g. "SOS Signal โ€” composite pattern, 3 groups."

๐Ÿž Debugging challenge

Below is a broken sequence, meant to blink the LED twice with a distinct pause between blinks. Copy it into the editor and find all three bugs before running it โ€” read it line by line first, the same way you'd review teammate's code, rather than just running it and guessing from the result.

pinMode(LED, OUTPUT);
digitalWrite(led, HIGH);
delay(400)
digitalWrite(LED, LOW);
delay(400);
digitalWrite(LED, HIGH);
delay(400);
digitalwrite(LED, LOW);

Write one sentence per bug once you've found them, explaining what was wrong and how you noticed it โ€” not just what you changed. (Hint: two of the three bugs are about exact spelling/capitalisation, and one is about a missing piece of punctuation you were told about in Lab 1.)

๐Ÿงฎ Precision practice โ€” three more targets

  1. Exactly 3 seconds, exactly 2 blinks. Design a sequence with precisely two ON periods that together with their delays sum to exactly 3000ms โ€” no more, no less.
  2. A "slowing down" pattern. Four ON/OFF pairs where each gap is longer than the last (e.g. 100ms, 250ms, 500ms, 1000ms) so the pattern visibly decelerates when you watch the log.
  3. A "speeding up" pattern. The exact reverse โ€” four pairs where each gap is shorter than the last โ€” and a one-sentence note on which felt harder to plan and why.

๐Ÿงฏ Common mistakes at this level

  • Branch sequences that are basically identical โ€” if your "low battery" and "normal" branches look almost the same, they're not really demonstrating two different outcomes; make the difference obvious in the pattern itself, not just in a comment.
  • Losing track of cumulative time in longer sequences โ€” for anything over 5โ€“6 lines, keep your timing table updated as you go rather than trying to hold the running total in your head.
  • Copy-paste drift โ€” when duplicating a group of lines (like repeating a flash pattern), it's easy to leave an old delay value in place by accident; re-check every duplicated line, don't assume the copy is correct.
  • Case-sensitivity mistakes creeping back in under longer, more complex code โ€” this simulator (like real Arduino code) never forgives a lowercase led, high, low, or a lowercase function name.

โœ… Definition of done

  • You built at least one pattern with 4+ ON/OFF changes, planned with a timing table before coding it
  • You hit an exact target runtime (6000ms) using arithmetic, not trial and error
  • Your SOS-style composite pattern runs correctly, with a longer pause between groups than within them
  • You wrote two distinct branch sequences for a two-outcome scenario, each clearly different in pattern, not just in its comment
  • You found and explained all three bugs in the debugging challenge, in your own words
  • Your saved project title describes both the pattern and the technique

๐Ÿ’ญ Reflection (a sentence or two, before you save)

When you compared your two branch sequences, what made one actually feel different from the other โ€” timing, number of flashes, or something else? If a real program had to pick between them automatically, what condition do you think it should check?

๐Ÿ’ก Tip: writing both branches of a decision as plain, runnable sequences before wiring up the real condition is exactly how experienced embedded developers avoid a common bug โ€” code where the "if" is correct but one of the branches was never actually tested in isolation. Carrying that habit into Lab 3, where you'll combine timing, branching, and a documented finished design into one capstone project, will save you real debugging time.

Expert Level Lab Instructions

Last updated: August 9, 2026

Building on Labs 1โ€“2: you can plan and hit exact cumulative timing, and you've hand-simulated a two-branch decision as two separate runnable sequences. This capstone asks you to put both skills together into one thing: a small, documented, multi-mode "device behaviour spec" โ€” the kind of planning document a real embedded engineer writes before touching actual hardware.

๐Ÿ” Quick recap โ€” still the same four patterns

pinMode(LED, OUTPUT); ยท digitalWrite(LED, HIGH); ยท digitalWrite(LED, LOW); ยท delay(ms); โ€” read top to bottom, no real loops or live conditionals. Everything in this capstone is still built from those four lines; what's expert-level is the planning, precision, and documentation around them, not new syntax.

๐ŸŽฏ The brief

Design a single imaginary device โ€” pick one: a smoke detector, a low-battery warning light, or a doorbell/notification light. Your device must have three distinct modes, each built as its own complete, separately-runnable sequence:

  • Idle / normal โ€” the calmest pattern, or no blinking at all beyond a brief startup flash
  • Active / notifying โ€” a clearly busier pattern than idle, something a person would actually notice
  • Critical / urgent โ€” the fastest, most insistent pattern of the three โ€” it should be obviously more urgent than "Active" when you watch the log, not just longer

๐Ÿงฉ Core requirements (all six)

  1. Three genuinely distinct sequences. Someone watching only the log โ€” no titles, no comments โ€” should be able to tell which mode is running just from the rhythm.
  2. A written spec sheet (a comment-style note block at the top of your code, since non-matching lines are safely ignored) listing, for each mode: its name, the real-world condition that would trigger it, and its total planned runtime in milliseconds.
  3. Exact timing math for every mode. Before running each sequence for the first time, calculate its total runtime by hand and write your predicted number into the spec sheet next to the mode โ€” then confirm it against the log.
  4. An escalation transition. Write a fourth sequence that plays Idle, then Active, then Critical back to back in one run, representing a situation getting worse over time โ€” with a short pause between each mode so they read as separate stages, not one blurred pattern.
  5. A deliberate, documented edge case. Choose one unusual scenario your device should handle (e.g. "what if Critical mode is triggered again while it's already running?") and write, in plain English in your spec sheet, what you think should happen โ€” this simulator can't actually test interrupting a running sequence, so this is a design decision you're documenting, not code you're able to prove here.
  6. A self-review pass (see below) completed and noted in your spec sheet before you save.

๐Ÿ› ๏ธ Suggested build order

  1. Pick your device and write your spec sheet first, as plain-English notes at the top of the editor, before writing a single real instruction line โ€” name your three modes and describe each one's intended "feel" in one sentence.
  2. Build Idle first, since it should be the simplest. Calculate its total time by hand, run it, and confirm.
  3. Build Active next. It must be clearly busier than Idle โ€” more changes, shorter gaps, or both. Calculate, run, confirm.
  4. Build Critical last of the three. Deliberately make it feel urgent: short, tight, repeated flashes. Calculate, run, confirm.
  5. Run all three back to back manually (one after another) and ask yourself honestly: could you tell them apart with your eyes closed, just from the rhythm? If two feel too similar, go back and widen the gap between them โ€” e.g. make Active's gaps noticeably longer than Critical's, not just "a bit" longer.
  6. Now build the escalation sequence: Idle's pattern, a short pause, Active's pattern, a short pause, Critical's pattern โ€” all in one continuous script. Calculate its full total runtime by hand before running it.
  7. Watch the escalation run and check the log against your prediction. If it drifts, find exactly which line's delay was miscounted rather than re-guessing the whole thing.
  8. Write your documented edge case as a plain-English note: what should happen if Critical is triggered again mid-run? There's no wrong answer, but it must be specific (e.g. "restart Critical from the beginning" vs "ignore the new trigger until the current cycle finishes") โ€” vague answers like "handle it properly" don't count.
  9. Do your self-review pass (below), and fix anything it surfaces.
  10. Save your project with a title naming the device and confirming the spec is documented, e.g. "Smoke Detector โ€” 3 modes + escalation, spec documented."

๐Ÿž Debugging challenge โ€” four bugs this time

The sequence below is meant to be an "Active" mode: three medium flashes, evenly spaced. Find all four bugs before running it โ€” review it line by line first, the way you would review a teammate's pull request, and write one sentence per bug once you've found them.

pinMode(LED, OUTPUT)
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(LED, LOW);
delay(300);
digitalWrite(LED, High);
delay(300);
digitalWrite(LED, LOW);
delay(300)
digitalWrite(LED, HIGH);
delay(300);
digitalWrite(LED, LOW);

(Hint: two are missing punctuation you were warned about back in Lab 1, one is a capitalisation slip, and the fourth is about counting โ€” look carefully at how many ON/OFF pairs this is actually supposed to be versus how many it has.)

๐Ÿ” Self-review pass โ€” do this before you save

Read back through your own spec sheet and code as if you were reviewing a stranger's submission, and answer honestly:

  • Could someone else read your spec sheet alone, without ever running your code, and correctly guess which mode feels most urgent?
  • Is your Active mode meaningfully different from Idle, and Critical meaningfully different from Active โ€” or did two of them end up nearly identical?
  • Does your escalation sequence's total time match what you calculated, or did you leave a stale prediction in your notes after making a late change?
  • Is your documented edge-case answer specific enough that two different people would build the same behaviour from it?

If any answer is "no" or "not really," fix that part before saving โ€” a self-review that doesn't change anything usually means it wasn't done carefully enough.

๐Ÿš€ Optional stretch goals

  • A fourth mode โ€” "Resolved/Reset" โ€” a short, calm confirmation pattern that plays once after Critical, representing the problem being cleared.
  • A timing budget. Set yourself a hard constraint (e.g. the full escalation sequence must complete in under 4000ms total) and redesign your three modes to fit inside it without losing their distinct feel.
  • Peer-readable notes. Rewrite your spec sheet as if it will be handed to another student who has never seen this simulator, with zero assumed context.

โœ… Definition of done

  • Three modes exist, each a complete standalone sequence, each clearly distinguishable by rhythm alone
  • A spec sheet documents each mode's name, trigger condition, and planned total runtime
  • Every mode's actual runtime was calculated by hand before its first run, and confirmed against the log
  • An escalation sequence plays all three modes back to back with clear separation between them
  • One edge case is documented with a specific, unambiguous plain-English answer
  • A genuine self-review pass happened and changed at least one thing before saving
  • All four debugging-challenge bugs were found and explained in your own words

๐Ÿ’ญ Reflection (write 2โ€“3 sentences before you save)

Which of your three modes was hardest to make feel genuinely different from its neighbour, and what specifically did you change โ€” timing, number of flashes, or both โ€” to fix it? If you added the "what if it's triggered again mid-run" edge case to a real board, what's the one piece of information the real code would need that this simulator can't give you?

๐Ÿ’ก Tip: the actual expert skill this capstone is testing isn't writing more digitalWrite lines โ€” it's the habit of documenting a design decision in plain language before code exists to enforce it, and then honestly checking your own work against that documentation instead of assuming it's fine because it runs without error. That habit is what separates code that works once from code a team can actually maintain.