{"id":47709498,"url":"https://github.com/trailcurrentoss/trailcurrentbearing","last_synced_at":"2026-04-16T01:01:12.546Z","repository":{"id":338332344,"uuid":"1156696417","full_name":"trailcurrentoss/TrailCurrentBearing","owner":"trailcurrentoss","description":"GNSS positioning module providing location and timing data over CAN bus","archived":false,"fork":false,"pushed_at":"2026-04-15T23:10:12.000Z","size":14910,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-16T00:26:45.239Z","etag":null,"topics":["can-bus","esp32","gnss","gps","iot","kicad","open-source","platformio"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trailcurrentoss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-13T00:12:28.000Z","updated_at":"2026-04-15T23:00:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"47e2946d-e40a-4871-ba33-7b5eb188e50a","html_url":"https://github.com/trailcurrentoss/TrailCurrentBearing","commit_stats":null,"previous_names":["trailcurrentoss/trailcurrentgnssmodule","trailcurrentoss/trailcurrentbearing"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/trailcurrentoss/TrailCurrentBearing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailcurrentoss%2FTrailCurrentBearing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailcurrentoss%2FTrailCurrentBearing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailcurrentoss%2FTrailCurrentBearing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailcurrentoss%2FTrailCurrentBearing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trailcurrentoss","download_url":"https://codeload.github.com/trailcurrentoss/TrailCurrentBearing/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailcurrentoss%2FTrailCurrentBearing/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31866357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"ssl_error","status_checked_at":"2026-04-15T15:24:39.138Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["can-bus","esp32","gnss","gps","iot","kicad","open-source","platformio"],"created_at":"2026-04-02T18:26:52.187Z","updated_at":"2026-04-16T01:01:12.537Z","avatar_url":"https://github.com/trailcurrentoss.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TrailCurrent Bearing\n\n![TrailCurrent Bearing](DOCS/images/bearing_product_render.png)\n\nGNSS (Global Navigation Satellite System) module for precise positioning, timing, and navigation. Part of the [TrailCurrent](https://trailcurrent.com) open-source vehicle platform.\n\n## Project Overview\n\nTrailCurrent Bearing is a standalone GNSS module that reads data from a DFRobot Gravity GNSS receiver via I2C and distributes it over the CAN bus for other modules to consume.\n\n**Example Use Cases:**\n- Digital clocks with precise time synchronization\n- Navigation and geolocation devices\n- Geospatial macros that control devices based on pinned locations\n- Vehicle tracking and positioning systems\n\n## Hardware Overview\n\n- **Microcontroller:** ESP32-S3 (Waveshare ESP32-S3-RS485-CAN board)\n- **GNSS Receiver:** DFRobot Gravity GNSS (I2C, multi-constellation)\n- **CAN Bus:** 500 kbps via TWAI driver (GPIO 15 TX, GPIO 16 RX)\n- **I2C:** GPIO 1 SDA, GPIO 2 SCL\n- **Flash:** 4 MB with dual OTA partitions\n\n### Components\n\n- DFRobot Gravity GNSS module (GPS + BeiDou + GLONASS)\n- Waveshare ESP32-S3-RS485-CAN module\n- JST XH connectors for power and signal distribution\n\n### KiCAD Library Dependencies\n\nThis project uses the consolidated [TrailCurrentKiCADLibraries](https://github.com/trailcurrentoss/TrailCurrentKiCADLibraries).\n\n**Setup:**\n\n```bash\n# Clone the library\ngit clone git@github.com:trailcurrentoss/TrailCurrentKiCADLibraries.git\n\n# Set environment variables (add to ~/.bashrc or ~/.zshrc)\nexport TRAILCURRENT_SYMBOL_DIR=\"/path/to/TrailCurrentKiCADLibraries/symbols\"\nexport TRAILCURRENT_FOOTPRINT_DIR=\"/path/to/TrailCurrentKiCADLibraries/footprints\"\nexport TRAILCURRENT_3DMODEL_DIR=\"/path/to/TrailCurrentKiCADLibraries/3d_models\"\n```\n\nSee [KICAD_ENVIRONMENT_SETUP.md](https://github.com/trailcurrentoss/TrailCurrentKiCADLibraries/blob/main/KICAD_ENVIRONMENT_SETUP.md) for detailed setup instructions.\n\n## Firmware\n\nBuilt with ESP-IDF (v5.5.x). Pure C, no Arduino framework.\n\n### Prerequisites\n\n```bash\n# Install ESP-IDF (one-time setup)\n# See https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/\n\n# Source the ESP-IDF environment\nsource ~/esp/v5.5.2/esp-idf/export.sh\n```\n\n### Build and Flash\n\n```bash\nidf.py set-target esp32s3\nidf.py build\nidf.py -p /dev/ttyACM0 flash monitor\n```\n\n### Release Binaries\n\nThe firmware produces two binary types for different deployment methods:\n\n| Binary | Purpose | How it's used |\n|--------|---------|---------------|\n| `bearing.bin` | App-only image | OTA updates via Headwaters (`esp_ota_write` validates the app header) |\n| `bearing_merged.bin` | Full flash image (bootloader + partition table + OTA data + app) | Web flasher (writes entire flash at offset 0x0) |\n\nAfter building, run the merge script to create both:\n\n```bash\nidf.py build\n./merge.sh\n```\n\nAttach **both** files to each GitHub release. The merged binary cannot be used for OTA — `esp_ota_end()` validates an app image header, and the merged binary starts with the bootloader, which would fail validation.\n\n### OTA Firmware Update\n\nFirmware can be updated over-the-air via the CAN bus trigger protocol:\n\n1. Send CAN ID `0x00` with the target device's last 3 MAC bytes\n2. The device joins WiFi (credentials must be provisioned first) and starts an HTTP server\n3. Upload the **app-only** firmware binary:\n\n```bash\ncurl -X POST http://esp32-XXYYZZ.local/ota --data-binary @build/bearing.bin\n```\n\nThe device writes to the inactive OTA partition and reboots with the new firmware. If the upload fails or times out (3 minutes), the device returns to normal operation.\n\n### mDNS Self-Discovery\n\nWhen CAN ID `0x02` is broadcast (typically by the Headwaters controller), all modules with WiFi credentials join the network and advertise themselves via mDNS:\n\n- **Service:** `_trailcurrent._tcp`\n- **TXT Records:**\n  - `type=bearing` — module type\n  - `canid=0x06` — primary CAN status message ID\n  - `fw=\u003cversion\u003e` — firmware version\n\nThe Headwaters controller queries mDNS to discover all online modules, then confirms each via `GET /discovery/confirm`. Modules disconnect from WiFi and return to CAN-only operation after confirmation or a 3-minute timeout.\n\n## CAN Bus Protocol\n\nAll messages use standard (11-bit) identifiers at 500 kbps.\n\n### Graceful Node Management\n\nThe CAN bus uses a TX_ACTIVE / TX_PROBING state machine that allows nodes to enter and leave the bus without impacting other nodes:\n\n- **TX_ACTIVE:** Normal operation at 30 Hz. If 3 consecutive TX failures occur (no ACK from peers), transitions to TX_PROBING.\n- **TX_PROBING:** Sends a single status message every 2 seconds. When a peer ACKs a transmission or incoming RX data is detected, transitions back to TX_ACTIVE.\n\nThis means unplugging a module causes it to gracefully back off, and plugging it back in resumes full-rate communication automatically with zero configuration.\n\n### TX Messages (GNSS Data)\n\n| ID | Name | DLC | Format |\n|----|------|-----|--------|\n| `0x06` | DateTime | 7 | `[year_H, year_L, month, day, hour, minute, second]` |\n| `0x07` | SatSpeedCourse | 6 | `[satellites, speed_H, speed_L, course_H, course_L, gnss_mode]` |\n| `0x08` | Altitude | 4 | `[alt_3, alt_2, alt_1, alt_0]` — altitude in meters * 100 |\n| `0x09` | LatLon | 8 | `[lat_sign, lat_2, lat_1, lat_0, lon_sign, lon_2, lon_1, lon_0]` — degrees * 10000 |\n\n**Encoding details:**\n- **Speed:** knots * 100 (uint16, big-endian)\n- **Course:** degrees * 10 (uint16, big-endian, rounded)\n- **Altitude:** meters * 100 (uint32, big-endian)\n- **Lat/Lon:** sign byte (0=positive, 1=negative) + 24-bit scaled value (degrees * 10000)\n\n### RX Messages (Control)\n\n| ID | Name | Purpose |\n|----|------|---------|\n| `0x00` | OTA Trigger | `[mac0, mac1, mac2]` — target device by last 3 MAC bytes |\n| `0x01` | WiFi Config | Chunked credential provisioning (see below) |\n| `0x02` | Discovery | Broadcast trigger for mDNS self-discovery |\n| `0x04` | Version Report | Sent on boot: `[mac3, mac4, mac5, major, minor, patch]` — reports running firmware version to Headwaters |\n\n### WiFi Credential Provisioning (CAN ID 0x01)\n\nWiFi credentials are sent in 6-byte chunks over CAN:\n\n1. **Start:** `[0x01, ssid_len, pass_len, ssid_chunks, pass_chunks]`\n2. **SSID chunks:** `[0x02, chunk_index, byte0..byte5]`\n3. **Password chunks:** `[0x03, chunk_index, byte0..byte5]`\n4. **End:** `[0x04, xor_checksum]`\n\nEach chunk carries up to 6 bytes. A 5-second timeout resets reception if a chunk is missed.\n\n## GNSS Modes\n\nThe DFRobot Gravity receiver supports multiple satellite constellation configurations:\n\n| Mode | Constellations |\n|------|---------------|\n| 1 | GPS only |\n| 2 | BeiDou only |\n| 3 | GPS + BeiDou |\n| 4 | GLONASS only |\n| 5 | GPS + GLONASS |\n| 6 | BeiDou + GLONASS |\n| 7 | GPS + BeiDou + GLONASS (default) |\n\n## Project Structure\n\n```\nmain/                       # ESP-IDF firmware\n├── main.c                  # GNSS polling, CAN TX/RX with state machine\n├── gnss.h / gnss.c         # DFRobot GNSS I2C driver\n├── ota.h / ota.c           # OTA updates \u0026 WiFi provisioning\n├── discovery.h / discovery.c  # mDNS auto-discovery\n├── CMakeLists.txt          # Build config\n└── idf_component.yml       # Managed dependencies (mdns)\n\nEDA/                        # KiCAD hardware design\n├── trailcurrent-gps-module.kicad_pro\n├── trailcurrent-gps-module.kicad_sch  # Root schematic (5 sheets)\n├── trailcurrent-gps-module.kicad_pcb\n├── mcu.kicad_sch           # MCU subsystem\n├── power.kicad_sch         # Power management\n├── can.kicad_sch           # CAN interface\n└── connectivity.kicad_sch  # GNSS interface\n\nCAD/                        # FreeCAD housing / 3D prints\npartitions.csv              # Dual OTA partition table\nsdkconfig.defaults          # Build defaults\n```\n\n## Manufacturing\n\n- **PCB Files:** Ready for fabrication via standard PCB services (JLCPCB, OSH Park, etc.)\n- **BOM Generation:** Export BOM from KiCAD schematic (Tools \u003e Generate BOM)\n- **JLCPCB Assembly:** See [BOM_ASSEMBLY_WORKFLOW.md](https://github.com/trailcurrentoss/TrailCurrentKiCADLibraries/blob/main/BOM_ASSEMBLY_WORKFLOW.md)\n\n## License\n\nMIT License - See LICENSE file for details\n\nThis is open source hardware. You are free to use, modify, and distribute these designs for personal or commercial purposes.\n\n## Contributing\n\nImprovements and contributions are welcome! Please submit issues or pull requests to the main repository.\n\n## Support\n\nFor questions about:\n- **KiCAD setup:** See [KICAD_ENVIRONMENT_SETUP.md](https://github.com/trailcurrentoss/TrailCurrentKiCADLibraries/blob/main/KICAD_ENVIRONMENT_SETUP.md)\n- **Library consolidation:** See [CONNECTOR_CONSOLIDATION_SUMMARY.md](https://github.com/trailcurrentoss/TrailCurrentKiCADLibraries/blob/main/CONNECTOR_CONSOLIDATION_SUMMARY.md)\n- **Assembly workflow:** See [BOM_ASSEMBLY_WORKFLOW.md](https://github.com/trailcurrentoss/TrailCurrentKiCADLibraries/blob/main/BOM_ASSEMBLY_WORKFLOW.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrailcurrentoss%2Ftrailcurrentbearing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrailcurrentoss%2Ftrailcurrentbearing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrailcurrentoss%2Ftrailcurrentbearing/lists"}