Modulino Movement + UNO Q - Motion Monitor
Live accelerometer and gyroscope readings stream from the Modulino Movement to the UNO Q.
Devices & Components
1
Modulino™ Movement
1
Arduino® UNO™ Q 2GB
Software & Tools
Arduino App Lab
Project description
Code
index
markup
HTML file
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 <title>Modulino Movement – Motion Monitor</title> 7 <link rel="stylesheet" href="styles.css" /> 8</head> 9<body> 10 <header> 11 <h1>🏃 Modulino Movement – Motion Monitor</h1> 12 <span id="status" class="status connecting">Connecting…</span> 13 </header> 14 15 <main> 16 <!-- Accelerometer --> 17 <section class="card"> 18 <h2>⚡ Accelerometer <span class="unit-hint">(g)</span></h2> 19 <div class="axis-grid"> 20 <div class="axis-row"> 21 <span class="axis-label">X</span> 22 <div class="bar-track"> 23 <div class="bar-center-line"></div> 24 <div class="bar-fill accent" id="bar-ax"></div> 25 </div> 26 <span class="axis-value" id="val-ax">0.00</span> 27 </div> 28 <div class="axis-row"> 29 <span class="axis-label">Y</span> 30 <div class="bar-track"> 31 <div class="bar-center-line"></div> 32 <div class="bar-fill accent" id="bar-ay"></div> 33 </div> 34 <span class="axis-value" id="val-ay">0.00</span> 35 </div> 36 <div class="axis-row"> 37 <span class="axis-label">Z</span> 38 <div class="bar-track"> 39 <div class="bar-center-line"></div> 40 <div class="bar-fill accent" id="bar-az"></div> 41 </div> 42 <span class="axis-value" id="val-az">0.00</span> 43 </div> 44 </div> 45 </section> 46 47 <!-- Gyroscope --> 48 <section class="card"> 49 <h2>🔄 Gyroscope <span class="unit-hint">(dps)</span></h2> 50 <div class="axis-grid"> 51 <div class="axis-row"> 52 <span class="axis-label">X</span> 53 <div class="bar-track"> 54 <div class="bar-center-line"></div> 55 <div class="bar-fill green" id="bar-gx"></div> 56 </div> 57 <span class="axis-value" id="val-gx">0.00</span> 58 </div> 59 <div class="axis-row"> 60 <span class="axis-label">Y</span> 61 <div class="bar-track"> 62 <div class="bar-center-line"></div> 63 <div class="bar-fill green" id="bar-gy"></div> 64 </div> 65 <span class="axis-value" id="val-gy">0.00</span> 66 </div> 67 <div class="axis-row"> 68 <span class="axis-label">Z</span> 69 <div class="bar-track"> 70 <div class="bar-center-line"></div> 71 <div class="bar-fill green" id="bar-gz"></div> 72 </div> 73 <span class="axis-value" id="val-gz">0.00</span> 74 </div> 75 </div> 76 </section> 77 78 <p class="last-updated">Last updated: <span id="last-updated">—</span></p> 79 </main> 80 81 <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script> 82 <script src="app.js"></script> 83</body> 84</html>
sketch
cpp
Arduino sketch
1#include <Arduino_RouterBridge.h> 2#include <Arduino_Modulino.h> 3 4ModulinoMovement imu; 5 6unsigned long last_read_ms = 0; 7const unsigned long READ_INTERVAL_MS = 100; 8 9String buildState() { 10 imu.update(); 11 return "{\"ax\": " + String(imu.getX(), 2) + 12 ", \"ay\": " + String(imu.getY(), 2) + 13 ", \"az\": " + String(imu.getZ(), 2) + 14 ", \"gx\": " + String(imu.getRoll(), 2) + 15 ", \"gy\": " + String(imu.getPitch(), 2) + 16 ", \"gz\": " + String(imu.getYaw(), 2) + "}"; 17} 18 19String rpc_get_state() { 20 return buildState(); 21} 22 23void setup() { 24 Bridge.begin(); 25 Modulino.begin(); 26 imu.begin(); 27 28 Bridge.provide("get_state", rpc_get_state); 29} 30 31void loop() { 32 unsigned long now = millis(); 33 if (now - last_read_ms >= READ_INTERVAL_MS) { 34 last_read_ms = now; 35 imu.update(); 36 Bridge.notify("motion_reading", 37 imu.getX(), imu.getY(), imu.getZ(), 38 imu.getRoll(), imu.getPitch(), imu.getYaw()); 39 } 40}
styles
css
Style file
1:root { 2 --bg: #0f1117; 3 --surface: #1c1f2a; 4 --border: #2e3244; 5 --accent: #4fa3e0; 6 --text: #e2e8f0; 7 --muted: #8892a4; 8 --green: #22c55e; 9 --red: #ef4444; 10 --radius: 10px; 11} 12 13* { box-sizing: border-box; margin: 0; padding: 0; } 14 15body { 16 font-family: 'Segoe UI', system-ui, sans-serif; 17 background: var(--bg); 18 color: var(--text); 19 min-height: 100vh; 20 padding: 1rem; 21} 22 23header { 24 display: flex; 25 flex-direction: column; 26 align-items: center; 27 gap: 0.5rem; 28 margin-bottom: 1.5rem; 29 text-align: center; 30} 31 32header h1 { font-size: 1.35rem; letter-spacing: -0.02em; } 33 34.status { 35 font-size: 0.8rem; 36 font-weight: 600; 37 padding: 0.25rem 0.75rem; 38 border-radius: 999px; 39 letter-spacing: 0.04em; 40 text-transform: uppercase; 41} 42 43.status.connected { background: var(--green); color: #fff; } 44.status.disconnected { background: var(--red); color: #fff; } 45.status.connecting { background: var(--muted); color: #fff; } 46 47main { display: flex; flex-direction: column; gap: 1.25rem; } 48 49.card { 50 background: var(--surface); 51 border: 1px solid var(--border); 52 border-radius: var(--radius); 53 padding: 1.25rem 1.5rem; 54} 55 56.card h2 { 57 font-size: 0.95rem; 58 font-weight: 600; 59 color: var(--muted); 60 text-transform: uppercase; 61 letter-spacing: 0.06em; 62 margin-bottom: 1rem; 63} 64 65.unit-hint { 66 font-weight: 400; 67 text-transform: none; 68 letter-spacing: 0; 69 color: var(--muted); 70 font-size: 0.8rem; 71} 72 73/* Axis rows */ 74.axis-grid { display: flex; flex-direction: column; gap: 0.75rem; } 75 76.axis-row { 77 display: grid; 78 grid-template-columns: 1.2rem 1fr 4.5rem; 79 align-items: center; 80 gap: 0.75rem; 81} 82 83.axis-label { 84 font-size: 0.85rem; 85 font-weight: 700; 86 color: var(--muted); 87 text-align: center; 88} 89 90/* Bidirectional bar — origin at centre */ 91.bar-track { 92 position: relative; 93 height: 14px; 94 background: var(--border); 95 border-radius: 999px; 96 overflow: hidden; 97} 98 99.bar-center-line { 100 position: absolute; 101 left: 50%; 102 top: 0; 103 width: 1px; 104 height: 100%; 105 background: var(--bg); 106 z-index: 1; 107} 108 109/* bar-fill sits at centre; width driven by JS; transform shifts it left or right */ 110.bar-fill { 111 position: absolute; 112 top: 0; 113 height: 100%; 114 width: 0%; 115 border-radius: 999px; 116 transition: width 0.08s ease, left 0.08s ease; 117} 118 119.bar-fill.accent { background: var(--accent); } 120.bar-fill.green { background: var(--green); } 121 122.axis-value { 123 font-size: 0.9rem; 124 font-variant-numeric: tabular-nums; 125 text-align: right; 126 color: var(--text); 127} 128 129/* Last updated */ 130.last-updated { 131 font-size: 0.8rem; 132 color: var(--muted); 133 text-align: center; 134} 135 136.last-updated span { color: var(--text); } 137 138@media (min-width: 600px) { 139 main { max-width: 700px; margin: 0 auto; } 140}
app
js
JS file
1var socket = io(); 2 3var statusEl = document.getElementById("status"); 4var lastUpdatedEl = document.getElementById("last-updated"); 5 6// Accelerometer elements 7var valAx = document.getElementById("val-ax"); 8var valAy = document.getElementById("val-ay"); 9var valAz = document.getElementById("val-az"); 10var barAx = document.getElementById("bar-ax"); 11var barAy = document.getElementById("bar-ay"); 12var barAz = document.getElementById("bar-az"); 13 14// Gyroscope elements 15var valGx = document.getElementById("val-gx"); 16var valGy = document.getElementById("val-gy"); 17var valGz = document.getElementById("val-gz"); 18var barGx = document.getElementById("bar-gx"); 19var barGy = document.getElementById("bar-gy"); 20var barGz = document.getElementById("bar-gz"); 21 22// Accelerometer full-scale: ±4 g (LSM6DSOX default) 23var ACCEL_MAX = 4; 24// Gyroscope full-scale: ±2000 dps (LSM6DSOX default) 25var GYRO_MAX = 2000; 26 27// Connection status 28socket.on("connect", function () { statusEl.className = "status connected"; statusEl.textContent = "● Connected"; }); 29socket.on("disconnect", function () { statusEl.className = "status disconnected"; statusEl.textContent = "● Disconnected"; }); 30socket.on("connect_error", function () { statusEl.className = "status connecting"; statusEl.textContent = "Connecting…"; }); 31 32socket.on("state_update", function (data) { 33 if (data) applyState(data); 34}); 35 36// Map a signed value to a bidirectional bar: 37// positive → bar grows rightward from centre (left: 50%, width fills right half) 38// negative → bar grows leftward from centre (right: 50%, width fills left half) 39function setBar(el, value, maxVal) { 40 var pct = Math.min(Math.abs(value) / maxVal * 50, 50); 41 if (value >= 0) { 42 el.style.left = "50%"; 43 el.style.right = ""; 44 el.style.width = pct.toFixed(1) + "%"; 45 } else { 46 el.style.right = "50%"; 47 el.style.left = ""; 48 el.style.width = pct.toFixed(1) + "%"; 49 } 50} 51 52function applyState(state) { 53 // Accelerometer 54 valAx.textContent = parseFloat(state.ax).toFixed(2); 55 valAy.textContent = parseFloat(state.ay).toFixed(2); 56 valAz.textContent = parseFloat(state.az).toFixed(2); 57 setBar(barAx, state.ax, ACCEL_MAX); 58 setBar(barAy, state.ay, ACCEL_MAX); 59 setBar(barAz, state.az, ACCEL_MAX); 60 61 // Gyroscope 62 valGx.textContent = parseFloat(state.gx).toFixed(2); 63 valGy.textContent = parseFloat(state.gy).toFixed(2); 64 valGz.textContent = parseFloat(state.gz).toFixed(2); 65 setBar(barGx, state.gx, GYRO_MAX); 66 setBar(barGy, state.gy, GYRO_MAX); 67 setBar(barGz, state.gz, GYRO_MAX); 68 69 lastUpdatedEl.textContent = new Date().toLocaleTimeString(); 70}
main
python
Python main
1import json 2import os 3 4from arduino.app_utils import App, Bridge 5from arduino.app_bricks.web_ui import WebUI 6 7_ui_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "ui") 8ui = WebUI(assets_dir_path=_ui_dir) 9 10state = {"ax": 0.0, "ay": 0.0, "az": 0.0, "gx": 0.0, "gy": 0.0, "gz": 0.0} 11 12 13def _call_mcu(method, *args): 14 try: 15 return json.loads(Bridge.call(method, *args)) 16 except Exception as exc: 17 print(f"[bridge] {method} error: {exc}") 18 return None 19 20 21def _broadcast(new_state, room=None): 22 if new_state and "error" not in new_state: 23 state.update(new_state) 24 ui.send_message("state_update", state, room=room) 25 26 27def on_connect(sid): 28 _broadcast(_call_mcu("get_state"), room=sid) 29 30 31def on_motion_reading(ax: float, ay: float, az: float, 32 gx: float, gy: float, gz: float): 33 state.update({ 34 "ax": round(ax, 2), "ay": round(ay, 2), "az": round(az, 2), 35 "gx": round(gx, 2), "gy": round(gy, 2), "gz": round(gz, 2), 36 }) 37 ui.send_message("state_update", state) 38 39 40ui.on_connect(on_connect) 41Bridge.provide("motion_reading", on_motion_reading) 42 43App.run()
Arduino App Lab
Modulino Movement – Motion Monitor
Real-time accelerometer and gyroscope dashboard from the IMU sensor.
🏃
Modulino Movement – Motion Monitor
Comments
Only logged in users can leave comments