Skip to content

SamSkjord/pico-tyre-temp

Repository files navigation

Pico Tyre Temperature Monitor - CAN Bus Version

Ask DeepWiki License

High-performance thermal tyre and brake temperature monitoring for Adafruit RP2040 CAN Bus Feather

Real-time thermal imaging at 10 fps with automatic tyre detection, brake pad temperature monitoring, and CAN bus output for vehicle integration.

Features

  • CAN Bus Output - Configurable CAN 2.0A (125K-1M kbps) for vehicle integration
  • Multi-Board Support - Up to 4 boards (one per wheel) on same CAN bus
  • Brake Temps - MCP9601 Type-K thermocouple support for brake pads
  • Fast - 10 fps thermal imaging with automatic tyre detection
  • Reliable - Automatic sensor recovery, watchdog protection
  • Safe - Integer overflow protection, bounds checking, flash verification
  • Visual Feedback - NeoPixel status LED with color-coded states

Hardware

Parts List

Component Qty Link
Adafruit RP2040 CAN Bus Feather 1 per wheel Pimoroni
MLX90640 Thermal Camera Breakout 1 per wheel Pimoroni
MCP9601 Thermocouple Amplifier (optional) 0-2 per wheel Pimoroni
Type-K Thermocouple (optional) 0-2 per wheel -
STEMMA QT / Qwiic cables as needed -

All three boards have STEMMA QT / Qwiic connectors - just daisy-chain with cables, no soldering for I2C.

Wiring

I2C (STEMMA QT cables, no soldering):

  • Feather QT port → MCP9601 (inner) → MCP9601 (outer) → MLX90640

Power and CAN (soldering required):

Feather Terminal Block     Vehicle
----------------------     -------
CAN-H                  →   CAN-H
CAN-L                  →   CAN-L
GND                    →   GND

Feather USB Header         Power Source
------------------         ------------
5V pad                 →   +12V via regulator or USB power

Add 120Ω termination resistor between CAN-H and CAN-L if sensor is at end of bus.

I2C Addresses

Device Address
MLX90640 thermal camera 0x33
MCP9601 inner brake temp 0x65
MCP9601 outer brake temp 0x66

Quick Start

1. Build

# Clone and build
git clone https://github.com/SamSkjord/pico-tyre-temp.git
cd pico-tyre-temp
git checkout canbus-feather

# Build (sets up toolchain paths automatically)
./build.sh

# Output: build/thermal_tyre_canbus.uf2

2. Flash

  1. Hold BOOTSEL button and plug in USB
  2. Copy build/thermal_tyre_canbus.uf2 to RPI-RP2 drive
  3. Feather reboots and starts running

3. Configure

Each sensor must be configured for its wheel position before installation.

Initial Setup (USB Serial)

  1. Connect sensor to computer via USB

  2. Open serial terminal (115200 baud):

    screen /dev/tty.usbmodem* 115200   # macOS/Linux
  3. Configure wheel position:

    WHEEL=0     # Front Left (CAN base 0x100)
    WHEEL=1     # Front Right (CAN base 0x120)
    WHEEL=2     # Rear Left (CAN base 0x140)
    WHEEL=3     # Rear Right (CAN base 0x160)
    
  4. Verify configuration:

    STATUS
    

    Output shows wheel ID, CAN base ID, and board serial number.

  5. Optional settings:

    EMISSIVITY=95    # Tyre emissivity (default 95 = 0.95)
    MODE=0           # 0=tyre detect, 4/8/16=fixed channels
    BROADCAST=1      # 1=auto 10Hz, 0=on-request only
    CANSPEED=500     # CAN bus speed (125/250/500/1000 kbps)
    

Configuration persists in flash across power cycles.

Multi-Sensor Setup

When setting up multiple sensors:

  1. Label each board with its wheel position before configuration
  2. Configure one at a time via USB before installation
  3. Record board serial numbers (shown in STATUS output) for remote configuration later

Remote Configuration (CAN)

Once installed, sensors can be reconfigured via CAN without USB access.

  1. Discover sensors - Send CONFIG_REQUEST (0x7F1):

    CAN TX: ID=0x7F1 Data=[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
    

    Each sensor responds with CONFIG_RESPONSE (0x7F2) containing its wheel ID and serial.

  2. Change wheel ID - Send CONFIG_SET_WHEEL (0x7F0):

    CAN TX: ID=0x7F0 Data=[serial0, serial1, serial2, serial3, new_wheel_id, 0, 0, 0]
    

    Where serial0-3 are the first 4 bytes of the target board's serial number.

  3. Change other settings - Similar format for 0x7F4-0x7F6:

    • CONFIG_SET_EMISSIVITY (0x7F4): [...serial..., emissivity, 0, 0, 0]
    • CONFIG_SET_MODE (0x7F5): [...serial..., mode, 0, 0, 0]
    • CONFIG_SET_BROADCAST (0x7F6): [...serial..., broadcast, 0, 0, 0]

Verification

After configuration, verify CAN output:

  1. Connect CAN analyser to vehicle bus
  2. Load pico_tyre_temp.dbc for signal decoding
  3. Check messages appear at correct base ID for wheel position:
    • FL: 0x100-0x11C
    • FR: 0x120-0x13C
    • RL: 0x140-0x15C
    • RR: 0x160-0x17C

Factory Reset

To reset a sensor to defaults (wheel 0, emissivity 95%, auto broadcast):

RESET

Quick Reference

Wheel ID CAN Base USB Command
Front Left 0 0x100 WHEEL=0
Front Right 1 0x120 WHEEL=1
Rear Left 2 0x140 WHEEL=2
Rear Right 3 0x160 WHEEL=3

CAN Bus Protocol

A DBC file (pico_tyre_temp.dbc) is included for use with CAN analysis tools (Vector CANalyzer, SavvyCAN, etc).

Message IDs

Each wheel has a unique base CAN ID with message offsets:

Message Offset Rate Content
TYRE_TEMPS +0x00 10Hz Left/Centre/Right temps, lateral gradient (detect mode)
TYRE_DETECTION +0x01 10Hz Detection status, confidence, width (detect mode)
BRAKE_TEMPS +0x02 10Hz Inner/outer brake temps, status
STATUS +0x10 1Hz FPS, firmware version, frame number
RAW_CH_A +0x18 10Hz Channels 0-3 temps (channel modes)
RAW_CH_B +0x19 10Hz Channels 4-7 temps (8/16 channel modes)
RAW_CH_C +0x1A 10Hz Channels 8-11 temps (16 channel mode)
RAW_CH_D +0x1B 10Hz Channels 12-15 temps (16 channel mode)
FRAME_DATA +0x1C On-demand Full 768-pixel thermal frame (256 segments)

Configuration Messages (Broadcast)

CAN ID Message Direction
0x7F0 CONFIG_SET_WHEEL RX
0x7F1 CONFIG_REQUEST RX
0x7F2 CONFIG_RESPONSE TX
0x7F3 FRAME_REQUEST RX
0x7F4 CONFIG_SET_EMISSIVITY RX
0x7F5 CONFIG_SET_MODE RX
0x7F6 CONFIG_SET_BROADCAST RX
0x7F7 DATA_REQUEST RX
0x7F8 CONFIG_SET_CANSPEED RX

Example: Front Left Wheel (ID 0)

CAN ID Message
0x100 Tyre temperatures
0x101 Tyre detection
0x102 Brake temperatures
0x110 Status
0x11C Frame data segments

Data Format

All multi-byte values are little-endian. Temperatures in tenths of °C (int16).

TYRE_TEMPS (8 bytes)

Byte 0-1: Left median temp (int16, tenths °C)
Byte 2-3: Centre median temp (int16, tenths °C)
Byte 4-5: Right median temp (int16, tenths °C)
Byte 6-7: Lateral gradient (int16, tenths °C)

BRAKE_TEMPS (8 bytes)

Byte 0-1: Inner brake temp (int16, tenths °C)
Byte 2-3: Outer brake temp (int16, tenths °C)
Byte 4: Inner sensor status (0=OK, 1=Disconnected, 2=Error, 3=Not Found)
Byte 5: Outer sensor status
Byte 6-7: Reserved

Full Frame Streaming

Request a full 768-pixel thermal frame by sending FRAME_REQUEST (0x7F3):

Byte 0: Target wheel ID (0-3, or 0xFF for any)
Byte 1-7: Reserved

The board responds with 256 FRAME_DATA segments (Base + 0x1C):

Byte 0-1: Segment index (0-255, uint16)
Byte 2-3: Pixel N+0 temp (int16, tenths °C)
Byte 4-5: Pixel N+1 temp (int16, tenths °C)
Byte 6-7: Pixel N+2 temp (int16, tenths °C)

Pixels are sent in row-major order (24 rows x 32 columns = 768 pixels). At 8 segments per main loop iteration (~10Hz), full transfer takes ~3.2 seconds.

Remote Configuration

Configure boards remotely via CAN (requires board serial number from CONFIG_RESPONSE):

CONFIG_SET_EMISSIVITY (0x7F4)

Byte 0-3: Target board serial (first 4 bytes)
Byte 4: Emissivity (10-100)
Byte 5-7: Reserved

CONFIG_SET_MODE (0x7F5)

Byte 0-3: Target board serial (first 4 bytes)
Byte 4: Channel mode (0=detect, 4, 8, or 16)
Byte 5-7: Reserved

CONFIG_SET_BROADCAST (0x7F6)

Byte 0-3: Target board serial (first 4 bytes)
Byte 4: Broadcast mode (0=request, 1=auto)
Byte 5-7: Reserved

CONFIG_SET_CANSPEED (0x7F8)

Byte 0-3: Target board serial (first 4 bytes)
Byte 4-5: CAN speed in kbps (125, 250, 500, or 1000, uint16 LE)
Byte 6-7: Reserved

Note: CAN speed change requires reboot to take effect.

CONFIG_RESPONSE (0x7F2) - sent in reply to CONFIG_REQUEST (0x7F1):

Byte 0: Wheel ID
Byte 1-4: Board serial (first 4 bytes)
Byte 5: Firmware version
Byte 6: Emissivity (0-100)
Byte 7: Channel mode

Status LED

Color Meaning
Green Normal operation
Yellow Warning (high gradient, thermocouple issue)
Red Sensor error (MLX90640 disconnected)
Blue CAN bus error
Purple Initialization/configuration mode
White flash Heartbeat (every second)

USB Serial Commands

WHEEL=n       Set wheel ID (0-3)
EMISSIVITY=n  Set emissivity (10-100, e.g., 95 = 0.95)
MODE=n        Set channel mode (0=detect, 4, 8, or 16)
BROADCAST=n   Set broadcast mode (0=on-request, 1=auto)
CANSPEED=n    Set CAN bus speed (125/250/500/1000 kbps, requires reboot)
STATUS        Show current configuration
RESET         Reset to defaults
HELP          Show available commands

Channel Modes

The sensor supports two types of operation: automatic tyre detection (mode 0) or fixed channel modes (4/8/16).

Mode 0: Tyre Detection (default)

Automatically detects tyre edges and reports left/centre/right zone temperatures. Best when the sensor has a clear view of the full tyre width with background on both sides.

CAN messages at 10Hz: TYRE_TEMPS, TYRE_DETECTION, BRAKE_TEMPS

Fixed Channel Modes (4/8/16)

Divides the sensor's 32 columns into equal groups spanning the full tyre width. Each channel reports the median temperature from the middle 4 rows (rows 10-13) of its column group. Use these modes when sensor mounting doesn't suit automatic detection.

4-channel mode - 8 columns per channel:

Columns:  0-7      8-15     16-23    24-31
          |--------|--------|--------|--------|
Channel:     0        1        2        3
          |------------- RAW_CH_A -------------|

CAN messages at 10Hz: RAW_CH_A, BRAKE_TEMPS

8-channel mode - 4 columns per channel:

Columns:  0-3    4-7    8-11   12-15  16-19  20-23  24-27  28-31
          |------|------|------|------|------|------|------|------|
Channel:    0      1      2      3      4      5      6      7
          |-------- RAW_CH_A ---------|--------- RAW_CH_B --------|

CAN messages at 10Hz: RAW_CH_A, RAW_CH_B, BRAKE_TEMPS

16-channel mode - 2 columns per channel:

Columns:  0-1  2-3  4-5  6-7 | 8-9 10-11 12-13 14-15 | 16-17 18-19 20-21 22-23 | 24-25 26-27 28-29 30-31
Channel:   0    1    2    3  |  4    5     6     7   |   8     9    10    11   |  12    13    14    15
          |--- RAW_CH_A ----||---- RAW_CH_B --------||---- RAW_CH_C ----------||---- RAW_CH_D --------|

CAN messages at 10Hz: RAW_CH_A, RAW_CH_B, RAW_CH_C, RAW_CH_D, BRAKE_TEMPS

Summary

Mode Columns/Channel CAN Messages (10Hz)
0 (detect) Auto zones TYRE_TEMPS, TYRE_DETECTION, BRAKE_TEMPS
4 8 RAW_CH_A, BRAKE_TEMPS
8 4 RAW_CH_A, RAW_CH_B, BRAKE_TEMPS
16 2 RAW_CH_A-D, BRAKE_TEMPS

All modes also send STATUS at 1Hz.

Broadcast Mode

Mode Description
1 (Auto) Continuous 10Hz transmission (default)
0 (Request) Only transmit when DATA_REQUEST (0x7F7) received

In request mode, send DATA_REQUEST with target wheel ID to trigger a single data transmission:

Byte 0: Target wheel ID (0-3, or 0xFF for all)
Byte 1-7: Reserved

Safety Features

  • Watchdog timer - 2s timeout, auto-recovery from hangs
  • Sensor recovery - Automatic re-initialization on failure (max 10 attempts)
  • Integer overflow protection - Safe temperature conversions
  • Flash verification - Confirms writes before proceeding
  • Bounds checking - Validates all inputs and array accesses

Build Requirements

Component Path Notes
Pico SDK ~/pico-sdk Clone from raspberrypi/pico-sdk
ARM Toolchain ~/arm-toolchain/arm-gnu-toolchain-14.2.rel1-* Official ARM release

Note: Homebrew's arm-none-eabi-gcc won't work due to missing newlib.

Manual Build

export PATH="$HOME/arm-toolchain/arm-gnu-toolchain-14.2.rel1-darwin-arm64-arm-none-eabi/bin:$PATH"
export PICO_SDK_PATH="$HOME/pico-sdk"

./tools/download_mlx_library.sh  # First time only
rm -rf build && mkdir build && cd build
cmake .. && make -j4

File Structure

pico-tyre-temp/
├── main.c                  # Main application loop
├── thermal_algorithm.c/h   # Tyre detection algorithm
├── can_bus.cpp/h           # CAN controller driver (C++)
├── config.c/h              # Flash configuration storage
├── status_led.c/h          # NeoPixel driver (PIO)
├── mcp9601.c/h             # Thermocouple driver
├── communication.c/h       # USB serial output
├── ws2812.pio              # PIO program for NeoPixel
├── build.sh                # Build script
├── CMakeLists.txt          # CMake configuration
├── CLAUDE.md               # Developer documentation
└── mlx90640/               # Melexis driver library

Troubleshooting

"ERROR: Could not detect MLX90640 sensor"

  • Check wiring (3.3V, not 5V!)
  • Verify 4.7kΩ pull-ups on SDA/SCL
  • Check I2C address (0x33)

CAN messages not appearing

  • Verify CAN-H/CAN-L wiring
  • Check 120Ω termination
  • Confirm baud rate matches receiver (default 500 kbps, check with STATUS command)

Red LED stays on

  • Sensor error - check MLX90640 connection
  • System will attempt recovery every 5 seconds

Blue LED

  • CAN bus error - check wiring and termination
  • May indicate bus-off condition

Version History

v2.0 (2025-01) - CAN Bus Version

  • New hardware - Adafruit RP2040 CAN Bus Feather
  • CAN output - 500 kbps CAN 2.0A replaces I2C slave
  • Multi-board - Support for 4 boards on same bus
  • Brake temps - MCP9601 thermocouple support
  • NeoPixel LED - Color-coded status indication
  • Safety features - Overflow protection, sensor recovery, watchdog

v1.x - Original Pico Version

  • Raspberry Pi Pico with I2C slave output
  • See main branch for original version

License

MIT License

Credits

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors