Outils › Simulateur dans le navigateur

Outils

Cette page n’est pas encore traduite : voici la version anglaise.

The browser simulator

See your model work before you install anything else. The browser simulator runs a model's behaviour — its state machines, its ```arche bodies, the messages on its links, a deployment's periodic threads — on a virtual clock, in plain JavaScript. It runs in four places, all the same code:

Where How
A terminal archec sim main.arche prints the trace
Any browser archec sim main.arche --html sim.html writes one page that runs it: open it, press Play
VS Code the ▶ Run button of the diagram panel, or Arche: Simulate in Diagram (arche.sim.run), or ▶ Simulate above a system
The Arche Store a package whose model does something has a Try it link: it runs in the visitor's browser

Arche's own simulator (archec test, archec run) is the reference: it runs the model's Python, charges each body its wcet, models the CPUs, the buses and faults, and checks test plans. The browser simulator is the quick look: nothing to install, and every step visible.

A first run#

message BLINK { on: bool }

component Blinker "Blinker" {
  out led: data sends BLINK
  var blinks: int32 = 0
  states {
    state Off {
      on-enter ```arche
        send led BLINK { on: false }
      ```
    }
    state On {
      on-enter ```arche
        blinks += 1
        send led BLINK { on: true }
      ```
    }
    Off -> On on "after 500ms"
    On -> Off on "after 500ms"
  }
}

component Led "LED" {
  in pin: data receives BLINK {
    handler BLINK -> show
  }
  var lit: bool = false
  fn show(on: bool) ```arche
    lit = on

}

system Desk { part blinker: Blinker part led: Led blinker.led -> led.pin }


```text
$ archec sim main.arche --for 1s
    0.000 ms  blinker: Off
    0.000 ms  blinker.led → led.pin  BLINK {"on":false}
  500.000 ms  blinker: Off → On
  500.000 ms  blinker.led → led.pin  BLINK {"on":true}
     1.000 s  blinker: On → Off
     1.000 s  blinker.led → led.pin  BLINK {"on":false}

--json gives the same trace as data: each event has its time t (ns) and its kind — send (from and to as part.port, msg, payload, arrive), state (part, from, to), ignored (a message the part had nothing to do with in its state), drop (sent on a port linked to nothing), log, note (something not simulated, once) and error (a division by zero, a loop that never waits). The same model gives the same trace, every time.

What it simulates#

  • Parts and links. Every part of the system (the active deployment's, or the first that does something; --system names one). A message sent on a port reaches every port linked to it, through composites and delegated ports (port out = mcu.i2c), after the links' latency.

  • One thing at a time per part. A message that arrives while the part is busy (in a wait) waits its turn, as in Arche.

  • State machines. A machine starts in its initial state (its on-enter runs at 0). A message fires the first transition on it from the current state, a state around it, or *, whose guard holds; then on-exit, the action, the new state, on-enter. A composite state enters its initial child; a pseudo choice takes its first transition whose guard holds. on "after 500ms" fires when the state has lasted that long. A guard may read the trigger's fields: Answered -> Waiting on PING [n > 2].

  • Bodies. The action language, all of it, translated to JavaScript (wait suspends the body; goto moves the machine; an integer divided by an integer is an integer). Python too, when it is the action language in other words (self.x = …, await wait(ms(2)), send(self.p, M(k=v)), await goto("S") — the same translation archec gen uses). TypeScript, all of it, as Arche runs it (handlers.md): its types blanked out, self the part, msg the message that triggered it, Arche's API (await wait(ms(2)), send(self.p, M({ k: v })), reply(…), await goto("S"), await self.f(x), the seeded rand()); a guard in a TypeScript component may be TypeScript ([msg.force > 0 && !self.open]).

  • What starts things. fn main runs from 0, as a thread of its own. A deployment's thread with a period and a step calls that function each period, the first at one period. A port's on-receive and its handlers (handler MSG -> fn, the parameters taken from the message's fields by name, else in order) run when a message arrives.

  • Sensors and actuators. A sensor's out port adds its noise to what it sends, saturates it by the field's range and rounds it to its resolution; an actuator's in port clamps its command to the field's range, and its output follows through its gain, lag and force-range (a drive line in the trace at each command, a plot in the page). A port's latency adds to its links'. The noise is drawn from a seed (--seed, simulation { seed }, else 1): the same run each time, and the page's Reset and time scrubber replay the same draws (spec).

  • Keyframes. --keyframe raised starts from that keyframe of the system: its parts' variables, its actuators' commands (a joint's position and velocity, a ball's or a free body's, are the plant's).

What it does not simulate#

It says so rather than guess: each of these is listed under "not simulated" (in the terminal, in the page, in VS Code) and is a note in the trace when it would have run.

  • Python the action language cannot say (a list, a library call, a if c else b…): the function does nothing and returns its type's zero.
  • A transition whose guard or action is such Python: it is never taken.
  • TypeScript that calls what Arche's simulator alone runs (recv, select, call, locks, bits, streams, timers, wait_until, clock): the body stops with an error that says so. Math.random and Date stop it too: a run must replay.
  • A trigger that is not a message and not "after …" (on boot_done, on "self test passed"): nothing in the simulation fires it — a test step or another part's goto would, in Arche.
  • Execution time (wcet), CPUs and their scheduling, buses and their bitrate, faults, plants and FMUs, memory and signals, test plans: Arche's simulator does those.

Compared with Arche's simulator on examples/live (test/websim.test.js does it when arche-cli is beside the checkout), the two give the same messages with the same payloads and the same state changes in the same order; the times differ by the execution times Arche charges.

The same model with its behaviour in TypeScript and in Python (examples/ts-handlers, and each template with its ```arche bodies written out in each language) gives the same trace in archec sim, the same verdicts against its MuJoCo plant, and the same verdicts in Arche's simulator; test/tsreach.test.js runs them all.

A timed transition, Braking -> Released on "after 25ms" (written to the Arche project as trigger: after 25ms), is taken by both simulators, whatever the handler language: after the delay spent in its state, restarted when the state is entered again, cancelled when it is left.

Against a plant#

archec sim main.arche --plant mujoco/plant_bridge.py runs the model against a plant that runs elsewhere: the MuJoCo one archec gen --target mujoco writes (see MuJoCo), or any command that speaks its JSON lines. The two go in lockstep, every period the plant says: its sensors' messages come in (an input in the trace) as if their parts sent them along their links, the model runs one period, and the messages it sent to the plant's actuators go back, each applied from its arrival. The plant reads and acts as the model says (noise, latency, ctrl range, lag…: MuJoCo and the bridge do it, from the same seed), and starts from --keyframe when one is given.

--test runs the model's test plans against the plant: each case is a run of its own, with a new plant, as long as its timeline. What the case reads is the parts' variables and states, so a controller keeps what it measured (controller.q1):

test-plan TP-ARM "The arm reaches its poses" {
  case TC-ARM-STEP "A second pose" {
    at 2s do controller.target_shoulder = -0.4
    at 4s expect abs(controller.q1 + 0.4) < 0.02
    at 4s expect never: controller.error > 1.5
  }
}
Moment What it does
at T do part.var = v sets the variable at T
at T do send(part.port, MSG(f=v)) sends the message from that port at T, along its links
at T expect c c is true at T (after what the plant sent at T)
within D expect c c is true at some time up to D after the last at
at T expect never: c c is never true from the at before to T, at each period
at T expect always: c c is true all along it

A condition is Python as the test plan writes it: part.var, part.state, the model's constants, numbers and strings, and or not, abs min max round; a chained comparison (a < x < b) is refused. A case that fails says what was not so, when, and the values it read; one that cannot run (a name it cannot read, a fault) says why. --json gives the cases with each check. The plants are tested so.

$ archec sim main.arche --plant out/mujoco/plant_bridge.py --test
Test cases against out/mujoco/plant_bridge.py
  ✓ TP-ARM TC-ARM-REACH Reach the first pose (2.000 s)
  ✓ TP-ARM TC-ARM-HOLD Hold it (3.000 s)
  ✓ TP-ARM TC-ARM-STEP A second pose (4.000 s)

3 of 3 case(s) passed

The page#

archec sim main.arche --html sim.html writes one file with everything in it: the sim program and its controls' data (JSON), the runtime, the live simulator and the player. It fetches nothing, so it works from a file, offline, or on any static host. The model runs in the page, live — as MuJoCo's viewer runs a scene, you can stop it, step it, slow it down and poke it:

  • Play / Pause (space), Step (→: to the next event), Step by a fixed time (Shift+→; ← goes back by it), Reset (R: from the start, nothing sent).
  • Speed, 0.1× to 10× (+ and −). 1× shows the model's shortest period or timeout a second (a second a second for a physical network alone); the slider's tooltip says how much.
  • Time: a scrubber over what has run. Going back replays the run up to that time, with what you sent at the times you sent it, so it is the same run; forward again, it plays the same. Sending something while back starts a new run from there: what you sent after that time is dropped. Home goes to 0.
  • Send a message: for each input port of a part that does something, the messages it receives (receives, its handlers; else its machine's triggers), each field a control — a number with its range (written, or its type's), a checkbox, an enum's values, a record's fields — checked before it is sent. Send now puts it on the port at the current time, as a link would bring it, after what happened at that instant; the trace shows it as you → part.port.
  • Push: when the system holds a physical network (ports with a potential and a flow, archec physics), the page integrates it with the events (RK4 at its solver step) and its sources — the parameter of a voltage, current, pressure or heat source, a force, a torque, a fixed temperature — and its in signals linked to nothing can be pushed: a step (added from now on) or a pulse (added for the time given).
  • Plots: any state (as a step line, its states on the axis), number variable, message field (the last value sent or received) or physical quantity, plotted live from 0 to now. The page starts with the network's first states, or the first state machine and variable.
  • Each message is a dot moving along its link; each part shows its state and its first variables in its box; the trace runs on the right.
  • --for sets how long the run lasts (10 s by default).

The live simulator is window.archeSim in the page's console: archeSim.inject('pong', 'rx', 'PING', { n: 7 }), archeSim.stepBy(10e6), archeSim.series.

In VS Code#

The diagram panel's ▶ button (or Arche: Simulate in Diagram) runs the current model's system live, in the extension (the webview evaluates nothing), and plays it on the diagram you already have: dots along the drawn links, the state on each block, the current state lit in a state-machine diagram. Beside it, the same controls as the page: pause (space), the next event (→), a step by a fixed time (Shift+→; ← back by it), reset (R), the speed (+ / −), the clock, the time scrubber (Home: to 0) and stop. ☰ opens the controls — send a message, push, plots, keys — and opens by itself when the model has an input port or a physical network. The trace goes to the Arche Simulation output as it runs. Edit the model and press ▶ again: it runs the new one.

In the store#

archec store site gives each package whose model does something a Try it link: p/<owner>/<name>.sim.html, the same page, built from the package's model. A visitor sees it run without installing anything.