Landroid Worx Mähroboter DIY GPS Tracking

| | Allgemein

DIY GPS Tracking für den Landroid Worx Mähroboter

Wenn du auf der Suche nach einer Möglichkeit bist, deinen Landroid Worx Mähroboter mit GPS Tracking auszustatten, dann bist du hier genau richtig. In diesem Beitrag zeige ich dir, wie du mit einem GPS Modul und einem ESP32 Controller dein eigenes Tracking-System für deinen Mähroboter realisieren kannst. Zusätzlich erkläre ich dir, wie du die Genauigkeit der GPS-Daten mittels eines Kalman-Filters in Home Assistant verbesserst.

Die verwendeten Komponenten

Für dieses Projekt habe ich folgende Komponenten genutzt:

  1. GPS Modul: GPS Modul von Amazon[*]
  2. ESP32 Controller: ESP32 Controller von Amazon[*]
  3. USB Winkelstecker: USB Winkelstecker von Amazon[*]

Glücklicherweise hat der Landroid im Batteriefach eine USB-Buchse, die wir nutzen können. Dafür benötigen wir entweder ein Winkelstück oder wir schneiden uns selbst ein Kabel zurecht, um den Anschluss herzustellen.

Installation und Konfiguration

Schritt 1: Hardware-Verbindung
  1. GPS Modul an den ESP32 Controller anschließen: Verbinde das GPS Modul gemäß den Anweisungen in der Produktbeschreibung mit dem ESP32 Controller.
  2. ESP32 mit dem Landroid verbinden: Nutze den USB Winkelstecker, um den ESP32 Controller mit der USB-Buchse im Batteriefach des Landroids zu verbinden.
Schritt 2: Software-Konfiguration

Um die Daten des GPS Moduls zu erfassen und weiterzuverarbeiten, verwenden wir ESPHome und Home Assistant. Hier ist die notwendige Konfiguration für ESPHome:

esphome:
  name: gps-sensor
  friendly_name: GPS Sensor
  on_boot:
    priority: -10
    then:
      - uart.write: !lambda |-
          // UBX command to set update rate to 5Hz
          uint8_t setRate[] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0x64, 0x00, 0x01, 0x00, 0x01, 0x00};
          uint8_t ck_a = 0;
          uint8_t ck_b = 0;
          for (int i = 2; i < sizeof(setRate); i++) {
            ck_a += setRate[i];
            ck_b += ck_a;
          }
          std::vector<uint8_t> command(setRate, setRate + sizeof(setRate));
          command.push_back(ck_a);
          command.push_back(ck_b);
          return command;
      - uart.write: !lambda |-
          // UBX command to enable SBAS
          uint8_t enableSBAS[] = {0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00};
          return std::vector<uint8_t>(enableSBAS, enableSBAS + sizeof(enableSBAS));
      - uart.write: !lambda |-
          // UBX command to set DGPS mode
          uint8_t setDGPS[] = {0xB5, 0x62, 0x06, 0x3E, 0x08, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
          return std::vector<uint8_t>(setDGPS, setDGPS + sizeof(setDGPS));
      - uart.write: !lambda |-
          // UBX command to disable static navigation
          uint8_t disableStaticNav[] = {0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
          return std::vector<uint8_t>(disableStaticNav, disableStaticNav + sizeof(disableStaticNav));

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:

api:
  encryption:
    key: "xxx"

ota:
  password: "xxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "Gps-Sensor Fallback Hotspot"
    password: "xxx"

captive_portal:

uart:
  tx_pin: 17
  rx_pin: 16
  baud_rate: 9600

gps:
  latitude:
    id: gps_latitude
    name: "GPS Latitude"
  longitude:
    id: gps_longitude
    name: "GPS Longitude"
  altitude:
    name: "GPS Altitude"
  speed:
    name: "GPS Speed"
  satellites:
    name: "GPS Satellites"
  course:
    name: "GPS Course"
  update_interval: 250ms

time:
  - platform: gps
    id: gps_time

text_sensor:
  - platform: template
    update_interval: 250ms
    name: "GPS Combined"
    id: gps_combined
    lambda: |-
      if (isnan(id(gps_latitude).state) || isnan(id(gps_longitude).state)) {
        return {};
      }
      char buffer[64];
      snprintf(buffer, sizeof(buffer), "%f,%f", id(gps_latitude).state, id(gps_longitude).state);
      return {buffer};

globals:
  - id: gps_initialized
    type: bool
    restore_value: no
    initial_value: 'false'

Home Assistant Konfiguration

Um die Daten aus dem ESP32 in Home Assistant zu nutzen und zu glätten, habe ich die folgende Konfiguration hinzugefügt:

input_text:
  gps_latitude_history:
    name: GPS Latitude History
    initial: ""
  gps_longitude_history:
    name: GPS Longitude History
    initial: ""
  kalman_filter_state:
    name: Kalman Filter State
    initial: ""    
  kalman_filter_state_lat:
    name: Kalman Filter Lat
    initial: "" 
  kalman_filter_state_long:
    name: Kalman Filter Long
    initial: "" 

Kalman-Filter Python Script

Um die GPS-Daten zu glätten, wird ein Kalman-Filter verwendet. Das folgende Python-Script implementiert diesen Filter:

# python_scripts/kalman_filter.py

latitude_history = hass.states.get('input_text.gps_latitude_history').state
longitude_history = hass.states.get('input_text.gps_longitude_history').state
kalman_state = hass.states.get('input_text.kalman_filter_state').state

if latitude_history:
    latitude

_history = latitude_history.split(',')
else:
    latitude_history = []

if longitude_history:
    longitude_history = longitude_history.split(',')
else:
    longitude_history = []

def init_kalman_filter(process_noise, measurement_noise, estimated_error, initial_value=0):
    return {
        'q': process_noise,
        'r': measurement_noise,
        'p': estimated_error,
        'x': initial_value,
        'k': 0
    }

def update_kalman_filter(kf, measurement):
    kf['p'] = kf['p'] + kf['q']
    kf['k'] = kf['p'] / (kf['p'] + kf['r'])
    kf['x'] = kf['x'] + kf['k'] * (measurement - kf['x'])
    kf['p'] = (1 - kf['k']) * kf['p']
    return kf

def float_to_hex(f):
    return ''.join('{:02x}'.format(b) for b in f.hex().encode('utf-8'))

def hex_to_float(h):
    return float.fromhex(bytes.fromhex(h).decode('utf-8'))

if kalman_state == "":
    if latitude_history and longitude_history:
        kf_lat = init_kalman_filter(0.1, 5, 1, float(latitude_history[-1]))
        kf_lon = init_kalman_filter(0.1, 5, 1, float(longitude_history[-1]))
    else:
        kf_lat = init_kalman_filter(0.1, 5, 1, 0.0)
        kf_lon = init_kalman_filter(0.1, 5, 1, 0.0)
else:
    kf_lat_state, kf_lon_state = kalman_state.split('|')
    kf_lat = init_kalman_filter(0.1, 5, 1, hex_to_float(kf_lat_state))
    kf_lon = init_kalman_filter(0.1, 5, 1, hex_to_float(kf_lon_state))

if latitude_history and longitude_history:
    latitude = float(latitude_history[-1])
    longitude = float(longitude_history[-1])
    kf_lat = update_kalman_filter(kf_lat, latitude)
    kf_lon = update_kalman_filter(kf_lon, longitude)

new_kalman_state = f"{float_to_hex(kf_lat['x'])}|{float_to_hex(kf_lon['x'])}"

hass.states.set('sensor.kalman_filter_output', 'on', {
    'latitude': kf_lat['x'],
    'longitude': kf_lon['x']
})

hass.services.call('input_text', 'set_value', {
    'entity_id': 'input_text.kalman_filter_state',
    'value': new_kalman_state
})

hass.services.call('input_text', 'set_value', {
    'entity_id': 'input_text.kalman_filter_state_lat',
    'value': str(kf_lat['x'])
})

hass.services.call('input_text', 'set_value', {
    'entity_id': 'input_text.kalman_filter_state_long',
    'value': str(kf_lon['x'])
})

logger.info(f"Kalman Filter updated: Latitude={kf_lat['x']}, Longitude={kf_lon['x']}")
logger.info(f"Kalman Filter state: {new_kalman_state}")

Automatisierung in Home Assistant

Um die GPS-Daten regelmäßig zu aktualisieren und den Kalman-Filter anzuwenden, habe ich die folgende Automation in Home Assistant erstellt:

alias: Update GPS Tracker
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.gps_sensor_gps_combined
condition:
  - condition: template
    value_template: "{{ not is_state('lawn_mower.schaf', 'docked') }}"
    enabled: false
action:
  - service: input_text.set_value
    data:
      entity_id: input_text.gps_latitude_history
      value: >-
        {{ (states('input_text.gps_latitude_history').split(',')[-(n-1):] |
        join(',')) + ',' +
        states('sensor.gps_sensor_gps_combined').split(',')[0] if
        states('input_text.gps_latitude_history') else
        states('sensor.gps_sensor_gps_combined').split(',')[0] }}
  - service: input_text.set_value
    data:
      entity_id: input_text.gps_longitude_history
      value: >-
        {{ (states('input_text.gps_longitude_history').split(',')[-(n-1):] |
        join(',')) + ',' +
        states('sensor.gps_sensor_gps_combined').split(',')[1] if
        states('input_text.gps_longitude_history') else
        states('sensor.gps_sensor_gps_combined').split(',')[1] }}
  - service: python_script.kalman_filter
    data: {}
    response_variable: python_script_output
  - service: device_tracker.see
    data_template:
      dev_id: gps_tracker
      gps:
        - "{{ states('input_text.kalman_filter_state_lat') }}"
        - "{{ states('input_text.kalman_filter_state_long') }}"
      attributes:
        source_type: gps
variables:
  "n": 10
mode: queued
max: 15

Fazit

Mit dieser Anleitung kannst du deinen Landroid Worx Mähroboter mit einem DIY GPS Tracking System ausstatten und die Genauigkeit der Daten mittels Kalman-Filter verbessern. Allerdings muss erwähnt werden, dass der verwendete GPS Sensor nicht der beste ist und sehr ungenaue Daten liefern kann. Trotz dieser Einschränkung kann man damit in Home Assistant verfolgen, welche Strecken der Mähroboter abgefahren hat. Interessant wäre es sicherlich, auch andere Module zu testen, wie z.B.

Diese Lösung ist natürlich nicht nur für Mähroboter geeignet. Sie lässt sich ebenso für andere Zwecke einsetzen, z.B. in Verbindung mit einem GSM Modul im Auto, um die Fahrzeugposition zu verfolgen. Ich hoffe, dieser Beitrag hilft dir bei deinem Projekt. Wenn du Fragen oder Anregungen hast, hinterlasse gerne einen Kommentar. Viel Spaß beim Basteln und Happy Mowing!

Neueste Beiträge

Your MSPA Goes Smart – Step-by-Step to a DIY Smart Home Hot Tub (Wi-Fi Upgrade)

Introduction

In this article, I’ll show you how I successfully reverse-engineered the serial communication protocol of an MSPA Muse Carlton hot tub. The goal was to read remote control commands and send custom ones. I used an ESP32 Dev Board[*] for this. This protocol likely works with other MSPA models as well.

This article is for makers, home automation enthusiasts, and tech fans who enjoy diving deep into technical systems.


Weiter >>

Dein MSPA wird smart – Schritt-für-Schritt zum DIY Smart Home Whirlpool (WIFI/WLAN Upgrade) / Reverse Engineering eines proprietären UART-Protokolls am Beispiel eines Whirlpool-Steuergeräts (MSPA Muse Carlton)

Einleitung

In diesem Artikel zeige ich dir, wie ich das serielle Kommunikationsprotokoll eines MSPA Muse Carlton Whirlpools erfolgreich reverse-engineered habe. Ziel war es, die Fernbedienungsbefehle auszulesen und eigene Kommandos zu senden. Dafür kam ein ESP32 Dev Board[*] zum Einsatz. Dieses Protokoll funktioniert vermutlich auch bei anderen MSPA-Modellen.

Dieser Artikel richtet sich an alle Maker, Home-Automatisierer und Technik-Fans, die gern tief in die Technik eintauchen.


Weiter >>

Der perfekte Einstieg in die Welt der Vinyls: Der Denon DP-300F und 2 Alternativen

Warum Vinyl?

Vinyl erlebt seit einigen Jahren ein riesiges Comeback. Der warme, analoge Klang, das bewusste Musikhören und das Sammeln von Schallplatten faszinieren immer mehr Musikliebhaber. Dabei ist nicht nur das nostalgische Feeling ausschlaggebend, sondern vor allem auch der unverwechselbare Klangcharakter von Vinyl – ein Klang, der trotz moderner digitaler Verfahren nach wie vor viele Fans begeistert.

Denon DP-300F[*] – Der ideale Allrounder für Einsteiger

Der Denon DP-300F[*] ist nach wie vor ein beliebter vollautomatischer Plattenspieler im Einsteigerbereich. Sein automatischer Tonarm sorgt für einen schonenden Umgang mit Nadel und Platte – perfekt, wenn du ohne großen Aufwand direkt in den Vinylgenuss starten möchtest.


Weiter >>

Ein Leitfaden für Senioren: Günstige Smartphones bis 100 Euro – Unsere 4 Favoriten & Erfahrungsbericht einer maßgeschneiderten Senioren-Lösung – UPDATE 2024/25

In diesem Beitrag stellen wir dir vier günstige Smartphones vor, die aktuell (Stand Dezember 2024) für unter 100 Euro erhältlich sind. Zusätzlich teilen wir eine ganz besondere Geschichte aus dem Familienkreis: Wie wir eines dieser Geräte für die Oma meiner Verlobten eingerichtet haben, damit sie trotz ihrer Parkinson-Erkrankung gut damit zurechtkommt.


Weiter >>