Skip to content

bmilleare/luba-rtk-linux

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LubaBaseStationUpgrade — Linux

A Linux build of Mammotion's LUBA 1 RTK base-station firmware updater, which the vendor ships only for Windows and macOS.

There was nothing to reverse-engineer from scratch: the official Windows/macOS "tools" are the same PyInstaller-frozen Python program (Python 3.10 + PyQt6 + pyserial + protobuf). This package runs the vendor's own program bytecode (client/, qttoy/, msgbus/ — copied unmodified from the official Windows build) on Linux. The launcher only adds three small compatibility shims for Windows-only calls. Nothing in the flashing protocol, the device handshake, or the firmware image is altered.

Confirmed working on real hardware. Used on Ubuntu 24.04 to flash a LUBA 1 RTK base station from firmware 1.0.0.541.1.0.87 — the vendor tool's own post-write verification reported success.

⚠️ Compatible hardware: the RTK base station that shipped with the LUBA 1 only. This tool, and the bundled firmware image, target the LUBA 1 RTK reference station. It is not for the LUBA 2 / LUBA 2 series, Yuka, Luba mini, or any other Mammotion RTK. Do not run it against a different model — wrong firmware can brick the unit.


⚠️ Read this first (brick risk)

Flashing an RTK base station is inherently risky — a failed or wrong write can brick it.

  1. The code path here is the vendor's own, and it has now been used successfully on hardware — but you take the final risk.
  2. Always run probe.py first (read-only — it only asks the station for its version and cannot write to flash). Only run the real updater (run.py) once the probe confirms two-way communication.

If you are not comfortable with that, the zero-risk alternative is to run the official Windows/macOS tool in a VM with USB pass-through, or ask Mammotion support (support-eu@mammotion.com) to push the update.


TL;DR

# 1. one-time setup
python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt

# 2. plug the RTK into the PC with a USB-A -> USB-C *data* cable (see Troubleshooting),
#    power it on, then confirm two-way comms (safe, read-only):
python probe.py            # expect it to print the station's current version

# 3. flash (writes firmware via the vendor GUI):
python run.py              # pick "USB Serial" in the dropdown, click Upgrade

What the tool talks to

Base-station MCU STM32 (Cortex-M; firmware is a vector table into 0x08000000 flash)
USB-serial bridge CH341 — driver is built into the Linux kernel (ch341.ko); no install needed
Serial settings 230400 baud, 8N1, no flow control
Wire protocol Mammotion msgbus: A5 5A sync, sender/receiver/cmd, CRC16-CCITT (0x1021), ACK/NAK
Commands 0xC5 = get version (read), 0xC3 = LoRa/E22 bridge, 0xC4 = transmit firmware (write)
Firmware firmware/luba_v087_base.bin — 48,220 bytes, version 1.1.0.87, sha256 b7932fc0…0e12bac (also embedded in the app's Qt resources; the app flashes the embedded copy)

Setup

cd luba-rtk-linux
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt

Requires Python 3.10 (the vendor .pyc are 3.10 bytecode) and a desktop session (the updater is a PyQt6 GUI).


Usage

Follow the same physical steps as the official guide (mark the station's position, power it off, unplug it, connect it to the PC by USB).

1. Confirm communication (safe, read-only):

python probe.py                 # auto-detects the ttyUSB port
# or: python probe.py /dev/ttyUSB0

Expect a reply with the current version string. No reply → work through Troubleshooting below before going further. This step cannot brick the station; it only sends the get-version command.

2. Run the real updater (writes firmware):

python run.py

This opens the vendor GUI ("Upgrade Tools"). In it: select USB Serial in the Serial COM dropdown (that entry is your /dev/ttyUSB0; the GUI shows the port's USB description, not the /dev/tty… path), then click Upgrade.

  • You do not need the Driver button — that's the Windows CH341 driver installer; the driver is already in your Linux kernel.
  • Let it run to 100%. Nak, try again lines are normal — the protocol retries per frame. Do not unplug mid-write.
  • On success it re-reads the MCU and shows upgrade success — mcu version: ….

Then reinstall the station at its marked position and confirm it pairs with the mower.


Troubleshooting

These are the real snags hit bringing this up on a fresh Linux box, in the order you're likely to meet them.

1. Nothing happens when you plug it in (no /dev/ttyUSB0, no dmesg events)

Cause: a charge-only / USB-C-to-USB-C cable. The CH341 is USB 2.0; many USB-C↔USB-C cables carry no usable data pair, or hit USB-C host/host role ambiguity, so the device never enumerates at all.

Fix: use a USB-A → USB-C cable into a normal USB-A port. The USB-A end forces the PC to be host and the RTK to be the device. (The vendor GUI says the same thing: "Type-A to Type-C cable… Charging-only cables will not work.") Make sure the RTK is powered on — its indicator light should come on.

Verify enumeration:

lsusb | grep 1a86            # -> QinHeng CH340/CH341 serial converter
ls -l /dev/ttyUSB0

2. ttyUSB0 appears for a split second, then vanishes

Cause: brltty. Ubuntu's Braille-display driver grabs every CH340/CH341 chip (they share a USB ID) and kills the serial node. You'll see this in dmesg:

usbfs: interface 0 claimed by ch341 while 'brltty' sets config #1
ch341-uart ttyUSB0: ch341-uart converter now disconnected from ttyUSB0

Fix (you almost certainly don't use a Braille display):

sudo apt-get remove --purge -y brltty
sudo udevadm control --reload-rules
# then unplug and replug the RTK

3. Permission denied opening the port

The node is root:dialout. Add yourself to dialout:

sudo usermod -aG dialout "$USER"   # durable; takes effect after you log out/in
# or, just for this session:
sudo chmod a+rw /dev/ttyUSB0

4. ModemManager interfering

ModemManager probes new serial ports and can grab the CH341 mid-flash. Stop it for the duration:

sudo systemctl stop ModemManager
# (re-enable afterwards with: sudo systemctl start ModemManager)

5. The GUI used to crash on pnputil — already fixed here

On startup the vendor code shells out to the Windows driver installer (pnputil /add-driver CH341SER.INF /install) and, on Linux, died with FileNotFoundError: 'pnputil' before the Upgrade button unlocked. run.py now drops a no-op pnputil on PATH (the kernel already provides the driver, so "install" is genuinely a no-op). No action needed — just don't be surprised by a .shim-bin/ folder appearing next to run.py.

Reading kernel plug events

dmesg is often root-restricted on Ubuntu. To watch USB plug/unplug while debugging:

sudo sysctl kernel.dmesg_restrict=0   # then: dmesg -w
# (resets to 1 on reboot; or restore manually)

After a successful flash, probe.py returns ff ff ff

Expected. Once flashed, the new firmware boots into active RTK operation and stops answering the bare get-version handshake the old firmware did. This is not a brick — the GUI verified the new version during the flash. The real confirmation is that the base station now pairs with your mower.


What was changed vs. the official build

The vendor modules are byte-for-byte identical to the Windows build; only the launcher (run.py) adds shims:

  1. asyncio.WindowsSelectorEventLoopPolicy → aliased to DefaultEventLoopPolicy (the vendor sets it unconditionally at import; Linux's default loop is already a selector loop, so this is behaviourally equivalent).
  2. APPDATA env var → defaulted to ~/.local/share, so the app's config lands in ~/.local/share/LubaBaseStationTools/ instead of a Windows path.
  3. pnputil (Windows CH341 driver installer) → a no-op stub is placed on PATH so the vendor's startup driver-install step succeeds instead of crashing. The kernel already provides ch341.ko.

None of these touch the flashing protocol, the firmware image, or the device handshake.


Files

run.py               Linux launcher (runs the vendor entry point + 3 shims)
probe.py             Safe read-only comms test (get-version only)
requirements.txt     Pinned Linux dependencies
firmware/            Extracted firmware (reference; the app flashes its embedded copy)
client/ qttoy/       Vendor program bytecode (unmodified, Python 3.10 .pyc)
msgbus/              Vendor serial/protobuf message bus (unmodified)
LubaBaseStationUpgrade.pyc   Vendor entry point (unmodified)

Legal / provenance

This is an unofficial, community Linux build for interoperability. It is not affiliated with or endorsed by Mammotion.

The client/, qttoy/, msgbus/, LubaBaseStationUpgrade.pyc bytecode and the firmware image in firmware/ are Mammotion's property, redistributed here unmodified so Linux owners can update hardware they already own. All rights to those files remain with Mammotion. Only the original launcher code (run.py, probe.py) and this documentation are offered under the project LICENSE. If Mammotion would like the vendor files removed, open an issue and they will be taken down.

About

No description, website, or topics provided.

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages