3.8 KiB
AGENTS.md — SmartCar Demo
Project overview
LoongArch64 embedded autonomous smart car using OpenCV + NanoDet V10 model. Runs on-device (Loongson board) with cross-compilation from x86 Linux.
Build
# On the build host (x86 Linux):
mkdir build && cd build
cmake ..
make
- Cross-compilation target: LoongArch64 (
-march=loongarch64) - Toolchain:
/opt/loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-rc1.6 - C++ standard: 17
- OpenCV path (device-side):
/mnt/d/PPPProgram/smartcar/opencv_device/ cross.cmakeis included beforecmake_minimum_required— this is intentional.
Project structure
| Directory | Purpose |
|---|---|
src/ |
Source → compiled into common_lib (static lib) |
lib/ |
Public headers only (no .cpp) |
main/ |
Entry point → executable smartcar_demo1 |
docs/ |
Architecture docs (ARCHITECTURE.md is the design reference) |
build/ |
CMake build output (gitignored) |
Executable name: smartcar_demo1 (the CMake project name smartcar_demo2 is different — don't assume they match).
Excluded modules
These source files exist but are excluded from build:
vl53l0x.cpp— laser ranging module, hardware not connectedzebra_detect.cpp— classic zebra-crossing detection, replaced by NanoDet modelencoder.cpp— referenced in exclusion list but file does not exist in repo
Device-side operation
The onboard binary is controlled via text files in the working directory — no CLI args.
# On device:
sh ctl.sh init # initialize GPIO/PWM pins
sh ctl.sh start # start the demo
sh ctl.sh stop # stop and zero PWM
ctl.sh sets default config values by writing to files like ./speed, ./kp, ./steer_gain, etc. The running binary reads these files. start.sh uses LD_PRELOAD=./gpio_fix_final.so (GPIO workaround).
Configuration system
All config is via single-value text files in the working directory:
./speed(double) — target speed./start(0/1) — motor enable switch./debug(0/1) — when 1, reloads all config files every 7 frames./showImg(0/1) — LCD display toggle./deadband,./steer_gain,./center_bias— steering tuning./foresee— look-ahead row for steering./zebrasee— zebra crossing near-threshold./destfps— target framerate./kp,./ki,./kd— PID gains (currently not used; motor is open-loop)./mortor_kp,./mortor_ki,./mortor_kd— motor encoder PID (spellingmortoris intentional)
Architecture
9-step per-frame pipeline in CameraHandler() (src/camera.cpp):
- Capture frame (640×480 MJPEG → BGR)
- Optionally save image
- Vision line tracking (80×60 downscale → HSV+Otsu → floodFill → mid_line[60])
- Model inference every 2nd frame (NanoDet V10, 4 classes: cone/red/green/zebra)
- Zebra crossing state machine (NORMAL→STOP(4s)→COOLDOWN(5s))
- Steering servo control (PWM, deadband-filtered)
- Motor control (open-loop duty cycle, curve-based slowdown in turns)
- LCD rendering (
/dev/fb0mmap) - FPS logging
Key detail: Motor control is open-loop — MotorController::updateSpeed() and encoder PID exist in code but are never called from the main loop. Only updateduty() (direct PWM) is used.
Currently cones (cls=0), red lights (cls=1), and green lights (cls=2) are detected by the model but ignored in decision logic.
Style and conventions
- C++ files have no copyright headers and minimal comments — comments are ascii-box-style block comments when present
- Header guards use the form
#ifndef FILENAME_H_/#define FILENAME_H_ - Global state uses
externglobals (e.g.,g_cfg,g_steer_deviation,g_boxes) lib/contains .h files only;src/contains .cpp files only- No unit tests, no CI, no linting — this is embedded code tested on-device