Skip to content

SodaFMR/DECTmo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

116 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DECTmo

DECTmo is a DECT NR+ video and movement stack for the Freenove 4WD car.

Current production scope:

Video:
ESP32-P4-EYE camera -> HW H.264 encoder -> SPI -> nRF9151 TX
    -> DECT NR+ carrier 1669 -> nRF9151 RX -> UART H.264 -> PC/Raspberry Pi viewer

Movement:
nRF9161 TX DK buttons -> DECT NR+ carrier 1668 -> nRF9161 RX
    -> UART1 921600 -> Raspberry Pi Pico -> Freenove motors

The Raspberry Pi 5 USB-camera/JPEG UART video path remains as a fallback. The active video path is ESP32-P4-EYE H.264 over SPI because it gives much lower latency and better DECT bandwidth use.

Verified Boards

Video TX:     nRF9151 DK serial 1051219070, COM21/COM20
Video RX:     nRF9151 DK serial 1051202270, COM9/COM8
Movement TX:  nRF9161 DK serial 1050997258, COM17/COM18
Movement RX:  nRF9161 DK serial 1050926057, COM5/COM6
ESP32 camera: ESP32-P4-EYE, normally COM19 when USB connected

Manual .hex images for this scope are stored locally in:

firmware_hex/2026-05-26/

These .hex files are ignored by Git. See firmware_hex/README.md for checksums and manual reflashing commands.

Video Profile

Camera sensor:        OV2710 through MIPI CSI
Camera capture:       1280x720
Encoded stream:       1008x576 H.264
Frame rate target:    10 FPS
Bitrate target:       450 kbps
GOP:                  10
QP range:             30..44
ESP32 SPI packet:     64 bytes
ESP32 SPI payload:    54 bytes
SPI clock:            8 MHz
DECT video carrier:   1669
DECT MCS:             4
DECT TX power field:  13
Viewer UART baud:     921600

The nRF receiver reassembles H.264 NAL units, waits for SPS/PPS/IDR sync, and drops incomplete NALs after sequence gaps so corrupted frames do not reach the decoder.

SPI Wiring

ESP32-P4-EYE to video TX nRF9151:

ESP32 GPIO6   SCLK   -> nRF9151 P0.16
ESP32 GPIO8   MOSI   -> nRF9151 P0.17
ESP32 GPIO10  MISO   -> nRF9151 P0.19
ESP32 GPIO7   CS     -> nRF9151 P0.07
ESP32 GPIO34  READY  -> nRF9151 P0.06
ESP32 GND            -> nRF9151 GND

ESP32-P4-EYE camera control pins used by firmware:

GPIO11  camera XCLK
GPIO12  camera power enable
GPIO13  camera SCCB/I2C SCL
GPIO14  camera SCCB/I2C SDA

Use common GND. Keep SPI wires short.

Video Viewer

When all three video devices are on the laptop, use reset-sync:

python experimental/h264_dect/tools/h264_usb_receiver.py COM9 --baud 921600 --reset-nrf 1051219070 --reset-esp COM19 --stdout | ffplay -fflags nobuffer -flags low_delay -framedrop -probesize 32 -analyzeduration 0 -f h264 -

If COM9 shows no stream, try COM8; only one CDC port carries the H.264 output.

When the ESP32-P4-EYE and video TX nRF9151 are externally powered, plug only the video RX nRF9151 into the PC and run:

python experimental/h264_dect/tools/h264_usb_receiver.py COM9 --baud 921600 --stdout | ffplay -fflags nobuffer -flags low_delay -framedrop -probesize 32 -analyzeduration 0 -f h264 -

Validate a received stream:

python experimental/h264_dect/tools/h264_usb_receiver.py COM9 --baud 921600 --frames 180 --output dect_check.h264 --report-every 60
ffprobe -v error -f h264 -show_entries stream=codec_name,width,height -of default=noprint_wrappers=1 dect_check.h264
ffmpeg -v error -f h264 -i dect_check.h264 -f null -

Expected:

codec_name=h264
width=1008
height=576

No ffmpeg output means no decode errors.

Movement Path

Movement uses two nRF9161 DK boards:

Movement TX 1050997258: DK buttons -> DECT NR+ carrier 1668
Movement RX 1050926057: DECT NR+ carrier 1668 -> UART1 -> Pico UART0 GP1

Button mapping:

BTN4 -> forward
BTN3 -> right
BTN1 -> backward
BTN2 -> left

RX emits Pico motor bridge commands:

direction 1 -> F 34 250
direction 2 -> WHEELS 34 0 0 -34 250
direction 3 -> B 34 250
direction 4 -> WHEELS -34 0 0 34 250

Direct RX nRF9161 to Pico wiring:

nRF9161 DK UART1 TX / P0.29 / Arduino D1 -> Pico GP1 / UART0 RX
nRF9161 DK GND                         -> Pico GND
Pico GP0 / UART0 TX                    -> nRF9161 DK UART1 RX / P0.28 / Arduino D0 (optional)

The Pico firmware in control/pico_micropython_bridge/main.py listens on USB serial and UART0 GP1 at 921600 baud. Bench DECT button reception is verified; final car/Pico motor test is the next hardware check.

Build And Flash

Open an nRF Connect SDK terminal or set the toolchain environment first:

$tool='C:\ncs\toolchains\936afb6332'
$env:PATH="$tool\opt\bin;$tool\opt\bin\Scripts;$tool\usr\bin;$tool\nrfutil\bin;$env:PATH"
$env:ZEPHYR_TOOLCHAIN_VARIANT='zephyr'
$env:ZEPHYR_SDK_INSTALL_DIR="$tool\opt\zephyr-sdk"

Video TX nRF9151:

C:\ncs\toolchains\936afb6332\opt\bin\python.exe -m west -z C:\ncs\v3.3.0\zephyr build -b nrf9151dk/nrf9151/ns -d experimental/h264_dect/nrf9151_dect_video/build_tx -p always --extra-conf prj_tx.conf experimental/h264_dect/nrf9151_dect_video
nrfutil device program --firmware experimental/h264_dect/nrf9151_dect_video/build_tx/merged.hex --serial-number 1051219070 --family nrf91 --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE,verify=VERIFY_NONE,reset=RESET_SYSTEM

Video RX nRF9151:

C:\ncs\toolchains\936afb6332\opt\bin\python.exe -m west -z C:\ncs\v3.3.0\zephyr build -b nrf9151dk/nrf9151/ns -d experimental/h264_dect/nrf9151_dect_video/build_rx_9151 -p always --extra-conf prj_rx.conf experimental/h264_dect/nrf9151_dect_video
nrfutil device program --firmware experimental/h264_dect/nrf9151_dect_video/build_rx_9151/merged.hex --serial-number 1051202270 --family nrf91 --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE,verify=VERIFY_NONE,reset=RESET_SYSTEM

Movement TX nRF9161:

C:\ncs\toolchains\936afb6332\opt\bin\python.exe -m west -z C:\ncs\v3.3.0\zephyr build -b nrf9161dk/nrf9161/ns -d experimental/h264_dect/nrf91_movement_dect/build_tx_9161 -p always --extra-conf prj_tx.conf experimental/h264_dect/nrf91_movement_dect
nrfutil device program --firmware experimental/h264_dect/nrf91_movement_dect/build_tx_9161/merged.hex --serial-number 1050997258 --family nrf91 --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE,verify=VERIFY_NONE,reset=RESET_SYSTEM

Movement RX nRF9161:

C:\ncs\toolchains\936afb6332\opt\bin\python.exe -m west -z C:\ncs\v3.3.0\zephyr build -b nrf9161dk/nrf9161/ns -d experimental/h264_dect/nrf91_movement_dect/build_rx_9161 -p always --extra-conf prj_rx.conf experimental/h264_dect/nrf91_movement_dect
nrfutil device program --firmware experimental/h264_dect/nrf91_movement_dect/build_rx_9161/merged.hex --serial-number 1050926057 --family nrf91 --options chip_erase_mode=ERASE_RANGES_TOUCHED_BY_FIRMWARE,verify=VERIFY_NONE,reset=RESET_SYSTEM

ESP32-P4-EYE:

. C:\Espressif\tools\Microsoft.v6.0.1.PowerShell_profile.ps1
idf.py -C experimental/h264_dect/esp32_p4_h264_spi build
idf.py -C experimental/h264_dect/esp32_p4_h264_spi -p COM19 flash

Repository Layout

experimental/h264_dect/esp32_p4_h264_spi/
  ESP32-P4-EYE MIPI camera capture, H.264 encoding, SPI slave transport.

experimental/h264_dect/nrf9151_dect_video/
  nRF91 DECT video TX/RX firmware. TX reads ESP32 SPI packets. RX writes H.264 records to UART.

experimental/h264_dect/nrf91_movement_dect/
  nRF91 DECT movement TX/RX firmware. TX reads DK buttons. RX writes Pico movement commands.

experimental/h264_dect/tools/h264_usb_receiver.py
  PC/Raspberry Pi receiver tool. Reads UART H.264 records and pipes Annex-B to ffplay.

control/pico_micropython_bridge/main.py
  Pico motor bridge firmware.

control/pi5_controller/
  Legacy Raspberry Pi movement runtime, JPEG video sender/receiver, and local web control.

Legacy Pi Video Path

Fallback USB camera sender:

python3 control/pi5_controller/video_sender.py --video-uart /dev/ttyACM3 --quality 12 --fps 4 --verbose

Fallback browser receiver:

python control/pi5_controller/video_receiver_web.py --uart COM14 --dtr --rts

Open:

http://127.0.0.1:5001

Checks

python -m compileall control tests
python -m unittest discover -s tests

Safety

  • Lift car before movement tests.
  • Video and movement must stay on different carriers: video 1669, movement 1668.
  • Motor power must come from the car power system, not Raspberry Pi USB.
  • Do not run legacy web_control.py and movement_runtime.py together; both need Pico serial.
  • Keep AGENTS.md local only. It is operator context, not product source.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages