Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2026:bianca.popa1106:albert.guiman [2026/05/18 14:42]
127.0.0.1 external edit
pm:prj2026:bianca.popa1106:albert.guiman [2026/05/24 00:31] (current)
albert.guiman
Line 147: Line 147:
 | GPIO1 | Capacitive touch wake pin | | GPIO1 | Capacitive touch wake pin |
 | GPIO2 | Touch CS | | GPIO2 | Touch CS |
-| GPIO3 | LED |+| GPIO3 | LCD backlight PWM |
 | GPIO4 | LCD D/C | | GPIO4 | LCD D/C |
 | GPIO5 | LCD Reset | | GPIO5 | LCD Reset |
Line 160: Line 160:
  
   * The LCD, touchscreen controller, and SD card reader share a single SPI bus, but individual chip-select lines are used.   * The LCD, touchscreen controller, and SD card reader share a single SPI bus, but individual chip-select lines are used.
-  * GPIO3 is used as the LCD D/C pin. Since it is also a strapping pin on the ESP32-S3, the external circuit connected to it must not force an invalid boot state. If abnormal boot behavior is observed, this pin assignment should be reconsidered or the external circuit should be adjusted so it does not interfere with the required boot strapping state. +  * GPIO3 is used as the LCD backlight ​pin. Since it is also a strapping pin on the ESP32-S3, the external circuit connected to it must not force an invalid boot state. If abnormal boot behavior is observed, this pin assignment should be reconsidered or the external circuit should be adjusted so it does not interfere with the required boot strapping state. 
-  * GPIO43 and GPIO44 are typically associated with UART functionality. In this project, GPIO43 is assigned to the LCD backlight, therefore the debugging and console output through these pins will not be available.+  * GPIO43 and GPIO44 are typically associated with UART functionality. In this project, GPIO43 is assigned to the SD card chip-select line, therefore the debugging and console output through these pins will not be available.
   * GPIO1 is used as a wake-up input for user interaction after the device enters sleep mode.   * GPIO1 is used as a wake-up input for user interaction after the device enters sleep mode.
  
Line 179: Line 179:
   * C and C++ as the primary programming languages   * C and C++ as the primary programming languages
   * standard ESP-IDF build tools for flashing, monitoring, and configuration   * standard ESP-IDF build tools for flashing, monitoring, and configuration
 +  * **Android Studio**, **Gradle**, and **Kotlin** for the Android application
 +  * **Python** for offline map-tile conversion tooling
 +  * **QGIS** and **MapTiler** for preparing raster map tiles
  
 ==== Third-Party Libraries / Components ==== ==== Third-Party Libraries / Components ====
Line 194: Line 197:
   * **Squareline Studio**   * **Squareline Studio**
     * used for designing the UI     * used for designing the UI
 +  * **Android Bluetooth LE and Location APIs**
 +    * used by the phone application to scan for the bike computer and send current coordinates
 +  * **Python Pillow / NumPy**
 +    * used by the map conversion tool to convert raster tiles to RGB565
  
 ==== Wheel Module Firmware ==== ==== Wheel Module Firmware ====
Line 251: Line 258:
 === UI Design === === UI Design ===
  
-The user interface is implemented with **LVGL**. The planned ​UI contains ​at least the following ​tabs:+The user interface is implemented with **LVGL** and designed in **Squareline Studio**. The UI contains the following ​main screens:
  
   * **Metrics tab**   * **Metrics tab**
Line 272: Line 279:
 === Data integrity === === Data integrity ===
  
-The ESP-NOW packets contain a sequence number. The main module uses it to discard duplicate packets, ​ignore old packets for real-time speed display, ​and still account for valid out-of-order packets when updating accumulated metrics such as distance ​and total time.+The ESP-NOW packets contain a sequence number ​and cumulative wheel-module counters. The main module uses the sequence number ​to discard duplicate ​or stale packets. The cumulative counters make the main module logic simpler: once a packet is acceptedthe firmware can compute the delta in wheel rotations ​and moving time relative to the previous accepted packet. 
 + 
 +This approach keeps the main module tolerant ​of occasional packet loss and avoids complex packet reordering logic. Distance and moving ​time are derived from accepted wheel-module data, while speed uses the most recent valid wheel periods.
  
 === Storage Strategy === === Storage Strategy ===
Line 281: Line 290:
   * values are first buffered in RAM   * values are first buffered in RAM
   * the persistent storage is updated only at a predefined interval, or when necessary   * the persistent storage is updated only at a predefined interval, or when necessary
 +  * ride state is also saved when settings are changed or when the trip is reset
  
 === Maps Feature === === Maps Feature ===
Line 287: Line 297:
  
   * the user enters the Maps tab   * the user enters the Maps tab
-  * the main module ​pairs with the Android phone over BLE+  * the user presses the pairing button and the main module ​starts ​BLE advertising
   * the phone provides current location data   * the phone provides current location data
   * the firmware determines which map tiles are needed   * the firmware determines which map tiles are needed
Line 299: Line 309:
   * instead of storing PNG files that require runtime decoding, tiles are stored in a raw format such as **RGB565**   * instead of storing PNG files that require runtime decoding, tiles are stored in a raw format such as **RGB565**
   * this allows direct rendering to the display   * this allows direct rendering to the display
 +
 +The map viewport is implemented as an LVGL canvas placed inside the Squareline placeholder container. The canvas size is read at runtime from the UI object, so the viewport can be resized later in Squareline Studio without changing the rendering code. The current position marker is drawn in the center of the viewport, while the map tiles move underneath it.
 +
 +The firmware uses a fixed zoom level. The SD card path is organized as:
 +
 +  * ''/​sdcard/​maps/<​zoom>/<​x>/<​y>​.rgb565''​
 +
 +The RGB565 files are generated offline by a Python CLI tool. The tool receives an input slippy-tile directory, the original image format, and an output directory, then preserves the tile hierarchy while converting each tile to raw RGB565.
 +
 +To avoid redundant rendering work, the map is redrawn only when the projected location changes by at least a small pixel threshold. The canvas buffer is allocated from PSRAM because the full RGB565 viewport requires a relatively large contiguous buffer.
  
 === Wireless Coexistence === === Wireless Coexistence ===
Line 306: Line 326:
 === Power Management === === Power Management ===
  
-After a predefined period of inactivity+After a predefined period of inactivity the main module enters deep sleep, which in turn powers off most of the components, including the GPIO (which power the display). ​
-  * the display backlight is turned off +
-  * the main module enters deep sleep+
  
-The device can be woken up through the dedicated touch input.+The timeout is reset by wheel packets, BLE location activity, and user interaction. ​The device can be woken up through the dedicated touch input
 + 
 +==== Android Application ==== 
 + 
 +The Android application is intentionally simple. Its role is not to display the ride metrics, but to act as a bridge between the phone location provider and the ESP32-S3. 
 + 
 +The app: 
 +  * scans for the bike computer BLE service 
 +  * connects as a BLE central/​client 
 +  * subscribes to connection state changes 
 +  * receives GPS/network location updates from Android 
 +  * writes coordinates to the ESP32-S3 GATT characteristic 
 +  * runs the transfer logic in a foreground service so location updates can continue while the screen is off 
 + 
 +The Android UI exposes a single state-dependent action button: 
 +  * **Start scanning** when disconnected 
 +  * **Stop scanning** while scanning 
 +  * **Disconnect** when connected 
 + 
 +The app also shows the current connection state, the last phone coordinates,​ and a short log useful during development and testing.
  
 ==== Algorithms and Data Structures ==== ==== Algorithms and Data Structures ====
  
-Planned firmware mechanisms:+The main algorithms and data structures used by the project are:
  
   * **interval buffering**   * **interval buffering**
-    * an array / circular buffer of wheel-revolution intervals+    * the wheel module stores recent ​wheel-revolution intervals ​in a circular buffer in the LP-core firmware
   * **timeout-based motion detection**   * **timeout-based motion detection**
-    * repeated timer wake-ups without sensor events indicate that the bike has stopped+    * repeated timer wake-ups without sensor events indicate that the bike has stopped, reducing unnecessary HP-core wake-ups and radio transmissions
   * **metric computation**   * **metric computation**
     * speed is computed from wheel circumference and revolution interval     * speed is computed from wheel circumference and revolution interval
     * distance is computed from the number of wheel revolutions     * distance is computed from the number of wheel revolutions
 +    * ride time is moving time, based on wheel-module movement data rather than wall-clock time
 +    * metric values are stored internally in metric units, then converted for display if needed
 +  * **speed smoothing**
 +    * the displayed speed uses a lightweight smoothing factor to avoid sudden jitter from individual wheel periods
 +  * **sequence and cumulative-counter validation**
 +    * received packets are accepted only if they advance the last accepted packet state
 +    * cumulative wheel counters are used to compute deltas safely
   * **tile selection**   * **tile selection**
     * determine the subset of map tiles that cover the current visible screen area     * determine the subset of map tiles that cover the current visible screen area
 +    * compute slippy-map tile coordinates from latitude, longitude, and fixed zoom level
   * **deferred persistent writes**   * **deferred persistent writes**
     * maintain dirty flags and update NVS at controlled intervals     * maintain dirty flags and update NVS at controlled intervals
 +  * **BLE write queue**
 +    * the Android app keeps one active BLE write and one pending latest location, retrying if Android does not accept or complete a write
  
-==== Planned ​Source Structure / Implementation Notes ====+==== Source Structure / Implementation Notes ====
  
-This section will be updated after implementation.+The repository is split by module and by responsibility:​ 
 + 
 +  * ''​modules/​common/''​ 
 +    * contains the shared ESP-NOW packet definition used by both firmware projects 
 +  * ''​modules/​wheel_module/''​ 
 +    * ESP32-C6 firmware for the low-power wheel sensor node 
 +    * contains the HP-core application and the LP-core ULP program 
 +  * ''​modules/​main_module/''​ 
 +    * ESP32-S3 firmware for the display, UI, storage, ESP-NOW receiver, BLE location service, and map renderer 
 +  * ''​android-app/''​ 
 +    * Kotlin Android companion app used to scan, connect, and transmit phone coordinates over BLE 
 +  * ''​tools/''​ 
 +    * helper tools, including the raster-tile conversion CLI 
 + 
 +The main module firmware is divided into smaller layers: 
 + 
 +  * ''​constants/''​ 
 +    * board pin assignments,​ hardware configuration,​ and application constants 
 +  * ''​hardware/''​ 
 +    * SPI bus setup, ILI9341 display driver integration,​ XPT2046 touch integration,​ and SD card mounting 
 +  * ''​app/''​ 
 +    * application orchestration,​ UI callbacks, UI presenter, persistent storage, ride metrics, BLE location service, and map rendering 
 +  * ''​components/​ui/''​ 
 +    * Squareline Studio generated LVGL UI component 
 + 
 +The firmware follows an event-driven structure. ESP-NOW receive callbacks, BLE callbacks, timers, and UI callbacks post events to the main application event loop. The application task then updates ride metrics, persistence state, UI state, and map rendering from one place. ​This avoids doing heavy work directly inside interrupt-like or stack callback contexts. 
 + 
 +For the main module, the UI presenter converts internal data to user-visible labels. Ride metrics remain unit-system agnostic internally and are stored using metric units such as millimetres,​ microseconds,​ and kilometres per hour. Unit conversion and formatting are handled when values are presented in the UI. 
 + 
 +The map renderer avoids runtime PNG/JPG decoding on the ESP32-S3. Raster tiles are prepared on the computer, converted to raw RGB565, copied to the SD card, and streamed by the firmware. Missing tiles are rendered as a neutral background color so the screen remains usable even if the SD card does not contain every tile around the current position. 
 + 
 +The Android application uses a foreground service because Android may stop ordinary background work when the phone screen is off. The service owns scanning, GATT connection state, location updates, write retry logic, and the persistent notification,​ while the activity only displays state and exposes the action button.
  
  
 ===== Results and Conclusions ===== ===== Results and Conclusions =====
  
-**TBD**+The final system implements the main goals of the project:
  
 +  * the wheel module measures wheel revolutions while keeping the ESP32-C6 HP core asleep most of the time
 +  * the main module receives wheel packets over ESP-NOW and computes speed, trip distance, average speed, moving time, and total distance
 +  * settings and ride state are persisted across power cycles using NVS
 +  * the touchscreen UI provides metrics, maps, and settings screens
 +  * display brightness and sleep timeout are configurable
 +  * the main module can connect to an Android phone over BLE and receive live coordinates
 +  * offline raster map tiles can be converted to RGB565, copied to the SD card, and rendered on the display with a centered location marker
  
-===== Download =====+The project also demonstrates several important embedded-system trade-offs:
  
-<note warning> +  * batching wheel measurements reduces radio wake-ups and improves power efficiency 
-The project files will be uploaded here after implementation.+  * storing cumulative wheel counters in transmitted packets makes the receiver more robust and simpler 
 +  * moving map decoding offline is much more practical than decoding compressed image formats on the microcontroller 
 +  * PSRAM is important for framebuffer-like map rendering on the ESP32-S3 
 +  * BLE and ESP-NOW can coexist, but the firmware must be careful about radio configuration,​ connection state, and callback workload
  
-**[Download links placeholder]** +The result is a functional proof-of-concept wireless bike computer. It is not yet a polished commercial device, but it validates the complete data path: wheel sensing, low-power buffering, wireless transfer, metric computation,​ persistent state, phone-assisted location, and local map display. 
-</note>+ 
 +Future improvements could include: 
 + 
 +  ​a custom PCB instead of wiring modules manually 
 +  ​a more compact enclosure and better weather protection 
 +  ​battery measurement and charging-state display 
 +  ​more map zoom levels and route/​navigation features 
 +  * improved BLE reconnection behavior and phone compatibility testing 
 +  * additional ride statistics and data export 
 + 
 + 
 +===== Download ===== 
 + 
 +[[github.com/Albert24GG/​esp32-bike-computer/​ | Github Link]]
  
 ===== Bibliography / Resources ===== ===== Bibliography / Resources =====
Line 366: Line 467:
   * [[https://​www.espressif.com/​en/​products/​sdks/​esp-idf|ESP-IDF]]   * [[https://​www.espressif.com/​en/​products/​sdks/​esp-idf|ESP-IDF]]
   * [[https://​docs.lvgl.io/​|LVGL Documentation]]   * [[https://​docs.lvgl.io/​|LVGL Documentation]]
 +  * [[https://​squareline.io/​|Squareline Studio]]
   * [[https://​www.openstreetmap.org/​|OpenStreetMap]]   * [[https://​www.openstreetmap.org/​|OpenStreetMap]]
   * [[https://​wiki.openstreetmap.org/​wiki/​Slippy_map_tilenames|Slippy Map Tile Format]]   * [[https://​wiki.openstreetmap.org/​wiki/​Slippy_map_tilenames|Slippy Map Tile Format]]
 +  * [[https://​www.qgis.org/​|QGIS]]
 +  * [[https://​www.maptiler.com/​|MapTiler]]
 +  * [[https://​docs.maptiler.com/​guides/​self-hosting/​self-hosted-maps/​how-to-download-data-from-maptiler-website/​|MapTiler Self-Hosted Maps Documentation]]
 +  * [[https://​pillow.readthedocs.io/​|Pillow Documentation]]
 +  * [[https://​numpy.org/​doc/​|NumPy Documentation]]
 +  * [[https://​developer.android.com/​develop/​connectivity/​bluetooth/​ble/​ble-overview|Android Bluetooth LE Documentation]]
 +  * [[https://​developer.android.com/​develop/​connectivity/​bluetooth/​ble/​background|Android BLE Background Operation]]
 +  * [[https://​developer.android.com/​develop/​background-work/​services/​fgs/​service-types|Android Foreground Service Types]]
 +  * [[https://​kotlinlang.org/​docs/​home.html|Kotlin Documentation]]
  
 <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​ <​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​Export to PDF</​a></​html>​
 +
pm/prj2026/bianca.popa1106/albert.guiman.1779104544.txt.gz · Last modified: 2026/05/24 00:26 (external edit)
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0