Skip to content

Change Log

hippo5329 edited this page Oct 18, 2026 · 56 revisions

Change Log

What changed between releases. Every other page of this wiki describes the cockpit as it is; this page is the only one that records how it got there. Newest first.

Releases are the cockpit's rc-YYYYMMDD.N tags.

rc-20261018.1 — 2026-10-18

  • The tool's set saves to the board. Any key other than the test settings is written by the board into the env it boots from (ESP32, ESP32-S3, RP2040, RP2350, UNO Q), read back and checked; the answer gives the env checksum before and after. No esptool, picotool or OTA.
  • Inverts are live. set m1_inv 1 / set m1_enc_inv 1 flip that motor or encoder at once, with no restart; other keys restart the board into the tool, and lino_tool.py logs back in. Passwords, Wi-Fi keys and unknown keys are refused. See [[set saves to the board|Building-a-Real-Robot#set-saves-to-the-board]].
  • Short forms and Esc in the tool. m, mm, e, r, i, sn, st, g, h, b, and x for stop; Esc stops at once without Enter. acc has no short form. The Web UI's Command line takes them too.

rc-20261017.2 — 2026-10-17

  • SLAM: a LiDAR, masked or not, keeps SLAM Toolbox's values. The robot config's slam.narrow_fov_overrides apply only when /scan comes from a depth camera. Before, any scan under 270° took them, a masked LiDAR included, and on a real mecanum robot (215° of view) the map followed the odometry's heading creep: home within 0.01 m in the map, 0.8 m away on the floor. Without them the position held. The turn-rate cap while mapping from a narrow scan is unchanged and still applies to a masked LiDAR.
  • Motion guard: the floor the robot stood on is room. A leg home that ends behind a masked LiDAR sector is no longer cancelled as leaving the room.

rc-20261017.1 — 2026-10-17

  • EKF: no linear acceleration from the IMU. Every shipped config fuses yaw and yaw rate from the IMU, not ax/ay (imu0_config 12 and 13), as upstream linorobot2 does. With them, a robot whose odometry stopped (a dropped Wi-Fi session) ran off on its last acceleration. Bringup warns when a saved config still fuses them.
  • Nav2 goal test: LOST THE BASE. A leg whose /odom/unfiltered went quiet for 6 s ends with that verdict, instead of calling the filter's extrapolated pose a runaway.
  • Wi-Fi boards rejoin once. A udp4 board whose agent session was lost, and still gets no answer 10 s later, drops and rejoins its Wi-Fi once, so a link that is up but carries no answers gets a fresh association.
  • Logging out no longer breaks the stack. scripts/install_keep_ipc.sh installs a logind drop-in (RemoveIPC=no) on the robot computer: logind deleted the stack's shared memory when the user's last session ended, and every reader started after that got no data.
  • Room check out of a corner. A robot whose LiDAR has a blind sector finds its room from the last run's map (the scan matched to the saved map), and turns where it stands when the map covers the blind part. A short odometry pause makes a move hold still instead of refusing.
  • UNO Q clock resync. A resync is kept when the clock may have drifted further than the sync can err, so a slow board clock no longer piles up stamp lag (SLAM dropped scans).
  • Map Viewer: a goal's result stays on the status line; Nav2 going idle no longer overwrites it.
  • Console runs always end: a stream or request that drops reports a failure instead of hanging.

rc-20261016.3 — 2026-10-16

  • Battery sag in every 1-Click and in the Web UI. The run logs /battery from bringup to the end and reports the rest voltage, the worst reading and the step it fell in; the Operations card shows it under the verdict (live while test_acc reports), and the speed check prints its own. A rest reading is kept even when the first motion beats the logger's first sample.
  • A fenced exploration ends and drives home. Once the room's goals keep being refused and the map stops growing, exploration ends as explored and Nav2 drives the robot home, which may start near home.
  • Nav2 template: an in-place turn is progress, and a near goal cannot spin. PoseProgressChecker (required_movement_angle: 0.5) no longer aborts a slow turn at a goal's start. RPP projects its curvature point past the goal (use_fixed_curvature_lookahead, curvature_lookahead_dist: 0.6, interpolate_curvature_after_goal), so a robot just outside the goal tolerance drives through it instead of turning in place for minutes.
  • Map Viewer: the goal answers. A Nav Goal is a NavigateToPose action: the viewer shows its feedback (distance to go, time, ETA, recoveries) and its outcome (reached, aborted with Nav2's error, canceled); ⏹ Cancel goal cancels every goal, and a goal sent elsewhere is shown too. The scan is drawn from where the LiDAR is mounted (/tf_static).
  • Config saves keep the robot config's comments: the Web UI's save and drivetrain_report --write edit values where they stand.
  • Header Start 1-Click says why it did not start, on every tab: a toast, the action banner and a Not started badge.
  • SLAM & Nav: the buttons follow the stack that is running, one a 1-Click left up included, with a badge saying who started it.
  • A board not on USB is no longer described as plugged in (the UNO Q's on-board STM32, a Wi-Fi robot, the Sim MCU), and a plugged board never rewrites a real robot's controller. One robot-name rule, the backend's: letters, digits, _, - and ..
  • Bring-up: a step closes the tool session it opened; the LiDAR check starts bringup (and the agent) itself and stops it after; the bringup health check needs /scan on a robot with a LiDAR, and answers in a second or two.
  • Flash MCU flashes the image for the stack's distro, never a variant, and the UNO Q goes through flash_mcu.py over SWD like the other boards.
  • LiDAR page: a robot's UDP LiDAR is opened as bringup opens it, at every revolution; the LiDAR viewer keeps up with a 10 Hz scan instead of drawing two thirds of it.
  • Saved Maps: thumbnails are PNG (no browser shows a PGM); Save map writes to the one maps/ directory every reader uses.
  • Speed check: the console follows the run instead of going quiet for 90 s.
  • The tool: a Wi-Fi robot opens over the air unless the port it is given exists; an answer sharing the prompt's line is an answer; only base boots, and the tool is reached by the boot escape alone.
  • Smaller robot computers: a sane open-file limit in compose (on the UNO Q every jazzy ROS process carried 128 MB), the micro-ROS agent without ros2 run, /battery read through rosbridge; a timed-out ROS command takes its whole process group with it.
  • Scan matching: TF waits are measured in seconds, with the listener started before the scans.

rc-20261016.2 — 2026-10-16

  • A sensor on AUTO that the board did not find is no sensor. A real robot's topic gate no longer fails a magnetometer, current monitor or environment sensor left on AUTO that the board's bus scan did not find; one that is advertised is still checked.
  • RP2 boards flash from a cockpit that runs as a user. udev/60-linorobot2-usb.rules (installed by scripts/install_udev_rules.sh) gives the bootloader's USB device to the dialout group. Without it the flash stops with [NO USB ACCESS] and names the fix.

rc-20261016.1 — 2026-10-16

  • Every revolution of the LiDAR. The LD driver looks for a finished revolution 50 times a second; at 10 it lost about one scan in four from a 10 Hz LD19, and the motion guard stopped Nav2 for it. The 1-Click's topic gate holds /scan to 80 % of the LiDAR model's rate (8 Hz for an LD19), the motion guard's floor, instead of a flat 5 Hz.
  • A LiDAR that sees its own robot stops the run before Nav2 moves it. Returns inside the footprint that the mask does not cover make Nav2's collision monitor hold the robot still. The Nav2 step is refused and the bring-up's LiDAR step fails, both naming the sector to add to lidar.mask.sectors.
  • test_acc finds its room further away: one planned move, up to 2.5 m, to the spot with the most open floor, then the 5 cm steps; after a look around a blind sector only what is still unseen counts against the room. The EKF is set to the start pose before the drive home, and a refused drive home says why.
  • The motion guard hears the board's /battery (it subscribed in a way the board's topic never matched), and it is stopped first when a run ends, so a finished run no longer reports a stale scan.
  • kinematics.heading_turn_max_vel caps the turn to the goal heading that derived limits may set, for a robot that coasts past it.
  • The Arduino UNO Q from its Web UI: the board is found from inside its container, a robot name with a hyphen can be selected, the env is written over SWD from the page, Bringup is not stopped by files an earlier root run left behind, the status and the health check wait for a slow robot computer, and the micro-ROS agent runs at real-time priority.
  • A Wi-Fi robot's Bringup and 1-Click are not refused for "no board attached".
  • The virtual gamepad says "publishing" only once its publisher runs: on a slow robot computer the commands sent before then were lost.
  • The whole 1-Click output is kept in logs/<run>/oneclick.log, however the run was started.
  • --real-checks takes a simulated robot through a real robot's room check and motion guard.
  • Opening the tool waits until the board's tool reads lines, so the first command is not lost.

rc-20261015.2 — 2026-10-15

  • Every 1-Click option in the Web UI. Run options on the Operations tab: what to run (full, topics and drive, or topics only), SLAM or a saved map (AMCL), the map's name, exploration's time limit and minimum area, goals beyond the starting room, the fixed goal's round trips and tolerances, and the room safety distances. See Web UI Layout.
  • A real robot's Start asks first, and Abort shows in the header while a run goes. One run at a time: a second Start, or the board's tool during a run, is refused.
  • STOP works from every tab and says so in red when it did not reach the board. A page that finds the tool already open in another window says so.
  • The motion guard starts as soon as Nav2 is up. test_acc is not run after a trip, exploration stops at once, and a goal accepted after a trip is cancelled as it is accepted. The battery is judged by its voltage between min_v and max_v when the board reports no percentage; a LiDAR forwarded over Wi-Fi may pause 2 s.
  • The room follows the robot. Before anything moves: 0.40 m, or its radius + 0.15 m. For test_acc: its full-power second at top speed plus its radius, at least 1.0 m. The speed check needs the radius + 0.45 m and stops on anything in its way. A footprint sets the radius.
  • Safer motion on a real robot. Every move stops when /odom or the scan stops; the drive home after test_acc watches its blind sector against the start scan and sets the EKF to that scan's pose; a killed test_acc still stops the board and lets the agent go.
  • The bring-up checklist is stricter. A wheel that does not turn fails the wheel-speed step; the battery must lie inside min_v..max_v; the LiDAR step holds the motion guard's floor (80 % over 5 s); the speed step fails on a negative ratio or a gyro that disagrees with the LiDAR, which are wiring or mounting faults.
  • Derived limits: a measured slow step lowers the acceleration limit; a mecanum base strafes at 0.8 of its forward speed.
  • The command line picks the mode from the robot when --mode is not given.
  • Fixes: the design picker lists every shipped design; a robot whose last pin is unassigned simulates its devices again; a reloaded page sends the robot's own controller on Start; a robot with no scan source no longer fails saving a map.

rc-20261015.1 — 2026-10-15

  • test_acc in the 1-Click on serial robots too, and Measure the drivetrain first is on by default in the Web UI. On a serial robot the tool's console is the micro-ROS port, the agent is paused while the tool holds it, and after every env write the board's new session is proved by data, not by a listed publisher. See the six stages.
  • A LiDAR with a blind sector looks around before the room is judged. The robot moves onto ground already seen free, turns in place until every bearing has been seen, and comes back to where it was put. Before, the masked bearings counted as clear.
  • The drive home after test_acc finds a robot that turned a long way. The match starts from test_acc's own count of the move as well as from home's spot; the board's restarted odometry is no longer taken for a move; the first fix matches the median of three scans. A mecanum base slides home with its heading held, and the last turn is closed on /odom.
  • The motion guard's scan floor is 80 % over 5 s (was 85 % over 3 s): a robot computer busy for a moment while Nav2 starts no longer stops every goal; a LiDAR short of power is still stopped.

rc-20261014.3 — 2026-10-14

  • A motion guard on every real robot's exploration and goal legs. It cancels the goals when the LiDAR slows or stops or the battery runs down, and cancels any goal outside the room the LiDAR saw at the start (--explore-beyond-room lifts that). See the six stages.
  • The bring-up card's test_acc step runs on serial robots. Its loop verdict judges the wheel speed over 100 ms: one encoder count a tick made every gain set look the same.
  • The drive home after test_acc: the start snapshot waits for the LiDAR's mount, and the first fix must match a share of the snapshot and is refused when another pose fits nearly as well.
  • Entering the board's tool waits for the tool's prompt and retries once on a fresh open. The UNO Q's chip UID is read with its core halted.

rc-20261014.2 — 2026-10-14

  • Real-robot bring-up. A checklist on Hardware Tests and on the command line (robot_bringup.py) takes a new robot from its first power-on to its first 1-Click: sensors, battery, motors, wheel speed, LiDAR, then speeds and test_acc on the floor. The 1-Click holds a real robot until steps 1 to 5 have passed. See the checklist.
  • The board's tool answers every command in words: ok, fail and why, then done or stopped when a running command ends. A command that ends without doing its work says fail.
  • The Sim MCU's walkthrough mode (COCKPIT_TOOL_SIM_WALK=1): its wheel, IMU and magnetometer models let every bring-up panel and tool command be tried with no board.
  • Wheel speed: the wheel keeps running while you read the tachometer (it used to stop within seconds of the question), and a new max_rpm no longer fails the step.
  • test_acc waits up to 65 s for the board's first syslog line before it refuses: a board at rest sends one a minute, and the old 30 s window refused healthy boards.
  • SLAM on a narrow scan (a depth camera, a masked LiDAR) searches ±0.15 m, not ±0.25 m, and never retries a failed match at wider angles. Both had made the map jump: by the window's width, or by 30–70° onto the wrong wall. See Sensors and Maps.
  • The Nav2 goal test judges the home heading where the robot stops, not where Nav2's goal checker fired mid-turn. A tracked robot reported at +6.5° came to rest at −27°.

rc-20261014.1 — 2026-10-14

  • Collision monitor: base_shift_correction is off in every design. On a slow robot computer the scans arrive ahead of the odometry transform, the shift's lookup at each scan's stamp failed, and every failure stopped the robot (Failed to make progress). At 0.25 m/s and 10 Hz scans the uncorrected shift is at most 2.5 cm.

rc-20261013.4 — 2026-10-13

  • An RP2 board says which radio it has. Every RP2 image is built for the W boards, so a plain Pico also enumerates as a Pico W and looks like one to the firmware. The boot banner now ends with radio=: the wireless chip's number, revision and factory MAC when it answers (radio=cyw43439r5:…), none when the board has no radio, or noanswer when one was assumed and nothing answered.
  • The flash checks it against the config. A W config (picow, pico2w, xrp) on a board whose radio did not answer stops with [NO RADIO]; a plain config (pico, pico2) on a W stops with [IS A W], because a plain Pico's LED pin is the W's radio chip-select line.
  • The 1200-baud reset asks which board it is touching. Before every reset into the bootloader, the flasher reads the serial number behind the port, not only at the start of a flash. A retry after the ports were renumbered can no longer reboot another board.
  • Reference designs: the NULLLAB Maker-ESP32 and ESP32-UNO are removed. The Maker-ESP32 PRO stays, now with led: -1: the board has no user LED.

rc-20261013.3 — 2026-10-13

  • A Pico flash gets the time its image needs. picotool's load was stopped after a fixed 20 s. The RP2040 image is 1.34 MB and takes 23 s on a slow USB host controller, so the load was killed part-way and the board was left in BOOTSEL with half its flash erased. A load now gets 60 s plus 60 s per MB of image, and the flash log says how long it took.

rc-20261013.2 — 2026-10-13

  • The first pin turns the simulation off. A pin made a bare module a real robot, and Real mode ignored its simulation flags, but the saved config kept them: the Sensors tab still ticked them, Flash MCU wrote them into the env, the tool refused the wheels as simulated, and with simulated wheels every motor pin went to -1. A save that makes the robot real now turns every simulated device off and logs which ones; simulation cannot be switched back on for a real robot.
  • ↩ Back to a bare module: a real robot back to the bare module of its board, every pin unassigned and every device simulated, keeping its name, chassis and tuning.

rc-20261013.1 — 2026-10-13

  • Simulated wheels drive no real wheel. With the wheels simulated, the env written to a board sets every motor and encoder pin to -1, so no real motor can turn.
  • The hard-iron bias from the Sensors tab reaches the board, converted from µT to tesla; before, only a local build read it, and unconverted.
  • The Pico 2 mecanum design names its magnetometer ICM20948, the driver; AK09916 is the chip inside it and no driver.
  • The Sim MCU tool tests start the host firmware as the backend does; in the robot image they could not load it.
  • The serial-port and runtime hints name the MCU & Sim tab; the board-mismatch line no longer mentions app switches.

rc-20261012.5 — 2026-10-12

The Arduino UNO Q and Pico 2 mecanum designs on the MC200 chassis

  • Both mecanum reference designs are kits now: they bring the MC200 4WD mecanum chassis (80 mm wheels, 25 mm gear motors with Hall encoders) instead of the shared default chassis. The wheel diameter (0.075 m: the 80 mm wheels roll as 75 mm) and wheel centres (0.205 × 0.095 m) were measured on a built MC200 with the speed check against the LiDAR; rpm and encoder counts with a tachometer.

Speeds against the LiDAR

  • scripts/speed_check.py drives short mirrored steps (forward/back, spins, and on a mecanum base strafes) and compares the commanded speed, the wheels' odometry and the LiDAR's own track of the robot. Its verdicts name the config change: kinematics.wheel_diameter, kinematics.angular_scale on 2wd and skid-steer; a mecanum turn or strafe has no scale key, and it says so. It refuses to move without 0.6 m clear or while something else drives /cmd_vel. See Check the speeds against the LiDAR.

Sensors

  • BNO085: the gyro reads in rad/s. The SparkFun driver already returns rad/s, and the cockpit converted it from degrees again, so /imu/data's angular velocity was 57.3 times too small.
  • The BNO series is one chip in two roles. A BNO080/085/086 serves as the IMU and, with mag: BNO085, as the magnetometer too. Without its field the chip's own game rotation vector is the orientation; with it, the board's AHRS fuses gyro, acceleration and the field, with mag_bias / mag_soft applied, and the chip's own magnetometer calibration is off. A BNO055 driver (AMG mode, fused on the board) joins it, as an IMU and as a magnetometer. See Supported sensors.

Documentation

  • The Arduino UNO Q is no longer marked experimental.

rc-20261012.4 — 2026-10-12

One tool

  • On the stand and on the floor: ramp <wheel> finds each wheel's deadzone both ways with the robot lifted; every motor line flags DIR WRONG when a wheel counts against its power; a mecanum robot's acc adds a strafe run for its sideways limits; acc stops a drive whose terminal goes quiet for 2 s.
  • One firmware mode, and a tool behind it. base waits 3 s at boot (tool_wait) for tool + Enter on the console, or lino-tool on a Wi-Fi robot's ping port, and otherwise starts micro-ROS. The tool is a command shell: i2c, sensors, enc, motor <1-4|all> <pct> [secs], motors, acc [ms] [pct], adc, set / get, status, base. stop, s or an empty line stops a command. See The tool.
  • New tests. enc reads the encoders with the motors off (counts per revolution by hand); acc says what it will do and waits 3 s, takes a power cap, and stops on a wheel turning against its encoder; motors ends after one pass each way; every drive line shows the pack voltage.
  • Wi-Fi: a terminal and a guarded entry. lino-tool and the TCP terminal (2323) log in by md5(password:nonce) over the OTA password, which never crosses the network; a board without one refuses both. A drive started on the terminal stops when it goes quiet for 3 s. Pico W and Pico 2 W robots get an OTA password at their first USB flash too.
  • scripts/lino_tool.py restarts the board into its tool window (EN on an ESP32, BOOTSEL on an RP2, SWD on the UNO Q), runs commands or opens a terminal, sends stop on every exit, and goes back to base.
  • The old tool names still work. app=test_motors and the rest boot the tool and run their command, so scripts are unchanged; one the config refuses boots the robot firmware, as before.
  • Hardware Tests is the tool, in the page. Enter tool restarts the board into its tool (nothing written to the env) and the tab drives it: checks, a wheel picker with a power slider, live readouts, the terminal, and a STOP that stops the motors (stop, and lino-stop on Wi-Fi; Esc too; above the console bar on a phone). Its Stop used to close only the Monitor. The cockpit owns the session and the login (the page never holds the OTA password), keeps a drive alive only while a page is open, and opens the Sim MCU's tool too. The per-test upload buttons and the read-only Monitor are gone; Back to robot clears an app=test_* an older cockpit left.

Fixes

  • The Sim MCU's tool opens on a stack started without ROS_DISTRO. The tool panel's fallback distro is Lyrical, the default, as everywhere else.
  • The header fits a phone. At 390 px the header's reference stack pushed the page sideways.

rc-20261012.3 — 2026-10-12

  • A LAN mirror of the firmware. With COCKPIT_FIRMWARE_MIRROR set (comma-separated base URLs laid out as <base>/<tag>/<asset>), fetch_prebuilt.py tries each mirror before GitHub, with a 10 s timeout; the archive is checked against its manifest either way. The compose file passes the variable to the cockpit.
  • app=base is the robot firmware, not a tool. The tools' real-parts-only rule had reached the robot firmware too: its simulated IMU, battery and barometer went off and every board faulted seconds into each micro-ROS session.

rc-20261012.2 — 2026-10-12

  • Sensors are auto-detected. The reference designs name only the chips soldered on their boards; every add-on IMU, magnetometer, current sensor and barometer is AUTO, and so is the UNO Q's Qwiic IMU (a Modulino Movement or a BNO085). An empty bus means no sensor, never a simulated one; NONE still skips the scan.
  • The diagnostic tools use real parts only. test_sensors, test_acc and test_motors never create a simulated IMU or magnetometer, and the simulated battery and barometer stay off in a tool. test_motors scans the bus first, as the other two do.

rc-20261012.1 — 2026-10-12

  • A tool with no IMU says so. With no IMU or magnetometer, test_sensors had reported a magnetometer "initialized successfully" and test_acc a simulated IMU's acceleration; they now print No IMU / No magnetometer, and RANGE none for a sonar that is not fitted.
  • test_acc no longer sends the odometry off. The 1-Click pauses SLAM while it runs and sets the EKF back to its earlier pose once the robot is home; /odom had run off in a straight line and the next Nav2 goal aborted. ta_ms shortens each run phase (300-1000 ms) for a fast robot.
  • test_motors tm_only=N spins one motor until the env changes (tm_secs, 120 s), so a person can name the wheel; tm_only=5 drives all four.

rc-20261011.4 — 2026-10-11

  • Lyrical is the default ROS 2 distro (the current LTS). Jazzy stays supported; set ROS_DISTRO=jazzy for it. Firmware profile names are unchanged.
  • The topic check looks twice at a core topic that is short or silent before failing it.
  • SLAM that misses its activation is activated until it is active, so a stuck SLAM no longer leaves Nav2 without a map.
  • UNO Q: the battery reads right (the ADC pin was left a digital input: about 20 % low), and test_motors counts its encoders (it found the board's four counters taken).
  • test_motors runs at a quarter of full PWM by default (tm_pct) and polls the encoder lines directly (ENC POLL).

rc-20261011.3 — 2026-10-11

  • The simulated depth camera takes the configured camera's optics. A robot with an Astra Pro is simulated with its 58.4° view and 0.6 m near limit; it was a D435 whatever the config named.
  • /imu/data must reach 20 Hz in the topic check before SLAM and Nav2 (it was 7 Hz).
  • The UNO Q boots its firmware after a power cycle. With arduino-router off, the STM32's BOOT0 line floated and it started its ROM bootloader. The 1-Click sets the boot lines before every flash, and lino-stm32-boot.service sets them at boot.
  • The Yahboom YB-EET01 runs without a robot computer: micro-ROS over Wi-Fi, and its LiDAR forwarded over UDP from the board's LiDAR header.

rc-20261011.2 — 2026-10-11

  • The Astra Pro streams. Orbbec's driver crashed inside the image's OpenNI2 when the camera opened, so it never gave depth. The installer now also keeps the OpenNI2 library from Orbbec's SDK, and the camera runs on it; the depth topics are depth_raw/image and depth_raw/camera_info. Run install_orbbec_openni2.py again: the old install is not used.
  • Lyrical: no more stall at the goal on 2wd and skid steer. Nav2's rotation shim fought the final turn to the goal's heading, so a goal sometimes took 20-25 s more or aborted with the robot turned. The shim now makes that turn itself (rotate_to_goal_heading), as on Jazzy.
  • A Nav2 run comes home facing the way it started. The leg home is judged on heading as well as position, and waits for Nav2 to finish its last turn.
  • The NULLLAB boards' CH340G runs at 1.5 Mbaud, the rate the ESP32 firmware already carries on the General Driver's bridge; 921,600 left half of it unused.

rc-20261010.2 — 2026-10-10

The first release this log has a tag for; it also holds everything in the release of 2026-09-27, whose tag was retired.

New reference designs

  • Five more boards: the NULLLAB Maker-ESP32 (2WD), Maker-ESP32 PRO (mecanum or 4WD) and ESP32-UNO (2WD), the Pimoroni Motor 2040 (mecanum or 4WD) and the Cytron Maker Pi RP2040 (2WD). Their motor drivers (TB67H450, RZ7889, AT8833, DRV8833, MX1508) select the dual-PWM scheme.
  • GPIO 29 on the RP2040. The pin check accepts the RP2040's fourth ADC input for a battery sense, and refuses it on a Pico W, where it is the Wi-Fi chip's clock.

A real robot on the floor

  • The drive suite checks odometry against the room. With a LiDAR, each manoeuvre's distance and turn are measured by scan matching and compared with odometry's, and the run names the wheel_diameter and kinematics.angular_scale that would match. See odometry against the room.
  • A DDS domain per robot. base_controller.domain_id (ROS Domain ID on MCU & Sim) reaches the board's env, the Sim MCU, the 1-Click and every Web UI command. See a domain each.
  • A board's identity is read from a whole banner line. A read that stopped inside the uid could record a wrong board, and every later flash of the right one was refused.
  • The 1-Click checks the room before it moves a real robot. The LiDAR's whole circle must show nothing within 0.40 m (--clearance); a robot that is short of room is inched slowly clear, 5 cm at a time, or the run stops before anything else moves. See the six stages.
  • --test-acc tunes the robot during the run. The first map is built on half the Nav2 limits; then test_acc measures the drivetrain on the floor, the robot drives back to where it started by the LiDAR, and the run finishes on the PID gains and Nav2 limits derived from the measurement. A measured robot's Nav2 speed limits now follow the speed it actually reached.
  • lino-stop stops a tool. A UDP lino-stop to the board's ping port halts test_acc's motors at once. The motors are held off from the first line of the firmware's startup, so a robot no longer drives while it boots.
  • test_acc measures this robot. Its gains, wheel size and drivetrain come from the env, not the image; every identification step drives all the wheels out and back; the spins run at half power. test_motors reports speed through the robot's own wheel.
  • angular_scale on a 2wd. Tracks scrub in a turn like a skid steer; a tracked two-motor robot can now take the turn correction too.
  • Soft-iron magnetometer correction (imu_tuning.mag_soft_iron), after the hard-iron bias.

Sensors

  • Orbbec Astra Pro depth camera (depth_camera.model: astra_pro), through openni2_camera and Orbbec's OpenNI2 driver.
  • A real LiDAR on an ESP32 as /raw_scan, for a LiDAR wired to the board on a fast cable.
  • LiDAR Link on the Hardware tab: serial, topic or udp, offering only what the robot's link can carry. topic over Wi-Fi is refused.
  • BNO085: /imu/data publishes the chip's own fused orientation, gyro and acceleration at 50 Hz. Before this fix the BNO085 never reached /imu/data. The driver also re-arms its reports when the chip resets and restarts it after 3 s of silence.

Fixes

  • A topics-only check moves nothing. --topics-only --no-drive-test still sent a "mapping rotation" to the base. The spin now belongs to the Nav2 step only (Nav2 skipped while SLAM maps); a topics-only run runs no SLAM and never spins.
  • Waveshare General Driver: the wheels turn the right way. The design's motor pins were in the generic order, which ran both wheels backwards. IN A is now each motor's forward input (motor 1: 17 / 21, motor 2: 23 / 22), as linorobot2_hardware has it. A robot built from the design before this keeps its own pins: swap IN A and IN B on both motors, or apply the design again.

Wi-Fi robots off the cable

  • An ESP32 or ESP32-S3 Wi-Fi robot is flashed over USB once, then runs unplugged. It is found by its name: the cockpit pings its IP address, resolves <name>.local (mDNS) or broadcasts, and the board answers with its banner. 1-Click, Flash and tool switching write it over the air (the application and the env block), each write confirmed by the board after it reboots. Each robot gets its own OTA password at its first USB flash. A diagnostic tool's output streams to Monitor over syslog. See A Wi-Fi robot leaves the cable.
  • Wi-Fi keys first. A Wi-Fi robot with no Wi-Fi network in Secrets (or the seeded placeholder) is refused before anything is written ([NO WI-FI KEYS]): its first flash is what gives it the network.
  • Network Name and Robot IP Address on MCU & Sim: the robot's mDNS name (blank: the robot's name) and its address (detected at the first boot after its USB flash; edit to pin one).
  • i2c_detect needs the robot's I2C bus. It is enabled by default on a real robot and refused when the config assigns no I2C pins, as on a bare module: run the bare module in simulation mode first, then select the reference design, which brings the I2C and motor pins. See Building from a reference design, step by step.

Your robot

  • Name your robot first; everything after that saves to it. Type a name in the header's Robot field: its config is created from what is on screen. Every change in the configuration tabs is then saved as you make it, and Flash, 🚀 Start 1-Click and Bringup save first, so they run what you see. They used to run the last saved config, and edits waited for 💾 Save robot settings.
  • Reference designs are templates for your robot. Pick one under Reference Designs on MCU & Sim: its controller side (MCU, board, pins, motor driver, sensors, link) becomes your robot's and your chassis stays, so you can try another controller on the same wheels and motors. A kit (SparkFun XRP, Maker's Pet mini) brings its own motors, wheels and body, which you can change afterwards. Designs are no longer robots in the header's list.
  • A robot built from a design is real. It simulates nothing, Sim mode and the Sim MCU are refused for it, and Flash, 1-Click and Bringup need its own board. They used to fall back to the Sim MCU when no board was plugged in.
  • No Sim/Real switch. The header's selector and the Operations tab's Bringup Mode are gone. A badge beside the robot's name says what it is, 🧪 Simulation or 🔧 Real, and 1-Click and Bringup run it that way. A design, or a pin, makes a robot real.
  • In Sim mode, switch off any device the robot will not have. Every device is simulated by default. On the Sensors tab you can switch one off (IMU, magnetometer, barometer, battery sensor, sonar, LiDAR), and it is then absent, with no topic. Sim mode used to switch every simulation back on.
  • A board's simulated scan goes through the LD driver, topic mode included. raw_scan over micro-ROS is now turned into /scan by ldlidar_stl_ros2, as the serial and udp frames are. It used to be published and read by nothing, while the robot computer raycast the room itself. The robot computer's laser (sim_laser_node) now runs only beside sim_base_node, with sim_base:=true. A bare ESP32 with no LiDAR bridge has no /scan (bringup says so) instead of the robot computer's.
  • raw_scan needs a fast link: native USB, or a UART at 1.5 Mbaud or more (General Driver, UNO Q). topic on a 921600-baud UART (an ESP32 DevKit, the Yahboom's ESP32-S3 UART) is refused, because it starves the control loop. A bare ESP32-S3 now sends raw_scan over its native USB.
  • The Sim MCU raycasts a saved map itself (world: map), and the LD driver publishes its /scan. A board cannot hold a map, so a map world on a board is refused.
  • Fresher velocity commands on the board. /cmd_vel is subscribed best effort, keeping only the newest command. With the board's single micro-ROS input buffer the previous subscription kept the oldest command and dropped newer ones. Over Wi-Fi, a read with no wait now reads the socket (it never did), and the firmware drains everything ready each loop (rclc_executor_spin_all).
  • LiDAR mask margin. Each masked sector is widened by margin_deg (default 1°) on both sides, so the beam at a sector's edge no longer leaks the robot's own structure into every scan.
  • The robot computer can raycast for a board in Sim mode when asked (host_laser:=true, --host-laser), for an ESP32 or ESP32-S3 on a 921600-baud UART. A saved-map world on a board uses it too, where it used to be refused.
  • MCU topic monitor on the Bringup tab: the board's own topics, their measured rates, and a live rate or message stream for any one of them.
  • With no design, the board decides. Plug a board in and the cockpit makes a robot for it, lino_<mcu> (lino_esp32, lino_unoq): a bare module of that board, every device simulated, yours to rename. With no board at all, the cockpit starts on the Sim MCU robot (bare_sim), not on a design.
  • A bare module has no pin assigned but the LED. It can run in simulation; once any pin is assigned (a motor, an encoder, I2C, the battery, the sonar) the robot is real: Sim mode is refused and its board is needed. The one pin a bare module may also use is the one that carries a simulated LiDAR out (the GenDrv's LiDAR line).
  • Bringup starts the robot you just selected. Right after a switch it could launch the robot you had left.
  • "Robot is not moving" works. The Teleop tab's virtual gamepad now compares what it commands with the measured odometry. The check used to be a stub that never fired.

Hardware

  • Odometry on real wheels no longer jumps at start. On ESP32 and Pico boards the first wheel speed after boot could be enormous (the encoder's previous reading was never set), and the robot's odometry started kilometres away; with no motors connected a Yahboom read x = -4.7e11 m.
  • imu: AUTO waits for the board before saying "no IMU". The topic check looked for the IMU about a second after bringup started; a board that creates its IMU publisher a moment later was reported as having none. It now waits for the board's own /odom/unfiltered, then up to 8 s for /imu/data.
  • Hardware Tests on the Arduino UNO Q. Switching a tool writes the env over SWD, ⚡ Flash MCU installs unoq-<distro>, and 📡 Monitor reads /dev/ttyHS1. The UNO Q is in the Base Controller list, the cockpit recognises the board it runs on (it no longer switched a UNO Q to the Sim MCU), and its 4,000,000 baud survives a load and a save (Save used to write 921,600 over it). See Tab 6.
  • ⚡ Flash MCU follows the stack's distro. On a lyrical stack it flashed the jazzy image, for every board; it now flashes the -lyrical one.
  • The 1-Click flashes the Arduino UNO Q. Its STM32 is written over SWD from the board's own Linux, with the board's OpenOCD: the run checks whether the flash already holds this release's unoq-<distro> image, installs it if not, and writes the env block every run, read back and compared. Start the stack with docker-compose.unoq.yml on top. See Arduino UNO Q.
  • The UNO Q reference design is mecanum. The firmware drives eight PWM pins (A2, A3, D11 and D12 added) for two AT8236 boards, and the four encoders sit on eight distinct interrupt lines.
  • Arduino UNO Q firmware in the release. Every release now carries linorobot2-firmware-unoq-jazzy.tar.gz and linorobot2-firmware-unoq-lyrical.tar.gz: the STM32U585 image built with Zephyr, packaged like the other profiles and checked for its distro's /cmd_vel type before it is published. Fetch it with fetch_prebuilt.py unoq-<distro> and flash it over SWD from the board. See Arduino UNO Q.
  • AUTO with nothing on the I2C bus is no IMU and no magnetometer. The env block used to send AUTO as sim, so a real robot with an empty bus ran a simulated IMU beside its real wheels. The board now probes: a chip found is used, nothing found is none, and the topic check reports the robot as having no IMU instead of failing. See the bus wins.
  • Oradar MS200 LiDAR. lidar.model: ms200, read by the LD driver: the MS200 sends the LD19's packet, and the driver now accepts its point-count byte (the top three bits are reserved) and treats its reserved intensity codes (0-15) as no return. The Yahboom YB-EET01 reference, sold with one, names it. Verified against the protocol in a compiled driver; not yet on a real unit. See Which LiDAR and the MS200 on the Yahboom.
  • No IMU is an option. With imu: NONE the board publishes no /imu/data, bringup leaves the IMU out of the EKF, and the topic gate and the health card stop expecting it; the robot maps and navigates on its wheels and LiDAR. Before, imu: NONE ran the simulated IMU, on real wheels too. The IMU and magnetometer stay the simulation default, and no IMU can be chosen in Sim mode too. The Maker's Pet mini reference (no IMU) uses it. See No IMU.
  • Sim and real cannot mix; the result of a mix is useless. A robot config with some parts real and some simulated (a real IMU on simulated wheels, real wheels with a simulated LiDAR) is refused with [MIXED SIMULATION REFUSED], when the env block is written (nothing is flashed) and again at bringup. A real robot simulates nothing and runs in Real mode; Sim mode simulates the whole robot. The diagnostic tools are not judged by it. The Yahboom YB-EET01 reference simulated its magnetometer, LiDAR and environment sensor; it now simulates nothing. See Troubleshooting.
  • The bare ESP32-S3 config defaults to the chip's native USB (/dev/ttyACM0, console: usb), where the S3 image talks; it named /dev/ttyUSB0, a bridge port that carried nothing. UART0 stays an option per board (console: uart0, as on the Yahboom). See Simulation Mode & the Bare Module.
  • The diagnostic tools run on a real robot only, judged per tool: test_sensors is refused when the IMU is simulated, test_motors and test_acc when the wheels are, adc_calibrate when the battery is. The flasher stops with [TOOL REFUSED] before writing, and the firmware boots the robot application instead. Before this, test_sensors on a simulated IMU printed meaningless numbers.
  • A prebuilt image download that times out stops the run with DOWNLOAD TIMEOUT. It no longer flashes a cached image of an older release or points you at a local build; with no network at all, the cached image is still used and says so.
  • The Yahboom YB-EET01 reference is a 4WD skid steer on all four channels, so the reference designs cover the three drivetrains between them (GenDrv 2WD, Yahboom skid steer, Pico 2 mecanum). See Reference Designs.
  • The XRP reference robot is named xrp, after its file. It was bare_xrp, so the kit's firmware node and generated files carried the bare module's name. A copy already in your ~/linorobot2-config/ keeps the old name until you replace it from config/reference/.
  • The Operations tab card lists the stages in the order the pipeline runs them: SLAM, Nav2 (exploration or the goal round trips), the drive manoeuvres, then the map save.
  • Verified: the robot images on a Raspberry Pi 5 (arm64), and an ESP32-S3 on native USB carrying the simulated scan as a micro-ROS topic. See Installation & Docker.
  • SparkFun XRP robot kit reference design (xrp_config.yaml): the XRP Controller (RP2350B) on the kit's 2WD chassis, with its own wheel, motor and weight numbers and Nav2 limits derived from its motors. It runs the Pico 2 W release (pico2-jazzy, pico2-lyrical) with an XRP env block. See Reference Designs.
  • Maker's Pet mini robot kit reference design (makerspet_mini_config.yaml): an ESP32 on the BDC-30P motor board, 120 mm 2WD base, LD14P LiDAR, with the kit's own wheel, motor and weight numbers. It runs the ESP32 release (esp32-jazzy, esp32-lyrical) over Wi-Fi. See Reference Designs.
  • LDROBOT LD14P LiDAR (lidar.model: ld14p): read by the robot image's LDROBOT driver with the triangulation angle correction. The firmware sends the start command it needs (new env keys lidar_tx and lidar_init).
  • New motor driver type BDC30P (Maker's Pet BDC-30P): two PWM pins per motor.
  • A robot with a battery divider and no current sensor (current: NONE) publishes /battery. Before this fix it published nothing: the XRP, the Yahboom and the Maker's Pet.
  • The pico2 images are built for the RP2350B's 48 GPIO, so one image runs a Pico 2, a Pico 2 W and the XRP. New env key cyw43_pins sets the radio's pins on boards wired differently from a Pico 2 W. The battery ADC follows the chip's package.
  • The cockpit flashes an XRP with picotool and recognises it over USB.
  • Wire runs on whichever RP2 I2C controller owns the configured SDA/SCL pair. A pair that is not one controller's SDA and SCL is still rejected by the pin check, and the firmware reports it instead of halting.

Wireless

  • ota_password for ArduinoOTA: config engine, env partition, firmware and the Config Studio.

Web UI

  • The Config Studio's parameter headings, the AI Tuning Assistant title and the system-runtime card's tab links are drawn in the accent colour, and that card has its accent bar.
  • Save and import results in Config Studio and Setup are green on success and red on failure, and the Syslog panel's packet count and last sender are coloured.
  • MCU & Sim and Base are separate tabs; the header shows the build and git versions.
  • Any reference design can be chosen whatever board is plugged in; actions that write to a board check the plugged MCU first.
  • New Cockpit HUD logo.

Images

  • The robot image records the commit it was built from: the OCI org.opencontainers.image.revision label, and /ws/BUILD_COMMIT inside.
  • A release image fetches its own release's firmware. Its VERSION is the release tag; it used to carry the tree's <date>-dev, which made the 1-Click fetch the newest release's firmware instead.
  • The Arduino UNO Q firmware build waits for Zephyr's generated headers before building micro-ROS. On a busy machine it could fail with zephyr/syscall_list.h: No such file or directory.

Documentation

  • logs/<run>/progress.log tracks a 1-Click run: each stage with its time, every failure, and a heartbeat while a stage lasts. See Logs.
  • Each reference design now has its own page with its pins and a step-by-step setup; Reference Designs is the index.
  • Sensors and Maps lists every supported IMU, magnetometer and other sensor in tables.
  • Technical Details states that RP2 boards run micro-ROS over USB serial with the radio off.

Navigation and mapping

  • Nav2 follows upstream's own defaults: composition on both distros, 0.70 m inflation, MPPI's omni model on mecanum. Lifecycle bond timers are disabled in the composed container.
  • Frontier exploration (--explore, explore_lite) is the default for a new space: it searches through doorways, waits for the map to reach the robot, and returns home when done.
  • Navigating on a saved map (--map) localises with AMCL, started the way Nav2's localization_launch.py starts it.
  • A depth camera (RealSense, OAK-D, ZED) can be the scan source, or a second obstacle source beside a LiDAR.
  • RPLIDAR, YDLIDAR and XV-11 are read by their vendors' drivers. An unknown lidar.model stops bringup and names the valid ones; it used to be read as an LD19 at the wrong baud rate.
  • A LiDAR scan mask removes the robot's own body and masts from /scan.

Simulation

  • The Sim MCU: the real firmware running on the robot computer over micro-ROS, no board needed.
  • Simulated worlds by name (the wall room, or rooms to explore), and a saved map as a simulated world. Simulated rooms are never applied to a real robot.
  • A simulated battery with a 1 Hz /battery that sags under load.

Firmware

  • No robot feature is a build macro any more: sonar, INA219 and BMP280 are compiled into every image and enabled at boot from the env partition.
  • The DDS domain comes from the env partition.
  • A Pico W's LED is arduino-pico pin 64.
  • The IMU is fused on the board. The firmware's AHRS publishes /imu/data with its orientation; madgwick and /imu/data_raw are gone, and the EKF on the robot computer reads /imu/data.
  • Simulation is sim, not fake, the ROS 2 word: fake_wheel is sim_wheel, fake_ld19 sim_ld19, --mode fake --mode sim, and so on through the env keys and the firmware. The config migrator renames use_fake_* to use_sim_*, and the 1-Click says so first.
  • Two robots on one network. With topic_prefix the board puts the prefix on every frame_id it stamps as well as every topic name, and the launcher keys each params section by the node's full name: under a namespace the EKF had matched neither, started with no inputs and published nothing. The simulated sonar's messages also carry their frame (it was empty). See Multi-Robot Namespacing.

Pipeline

  • A 1-Click run stops the stack the previous run kept, restarts a SLAM or Nav2 that hung in its lifecycle once, and measures the exploring drive by odometry.

Clone this wiki locally