Add USBCANFD transport and visualize 0x391 door feedback

This commit is contained in:
zmv
2026-09-24 15:41:49 +08:00
parent 475fe2440b
commit 515a9f32d8
37 changed files with 1074 additions and 13 deletions
+25
View File
@@ -5,6 +5,8 @@
#include "door_risk.hpp"
#include "records.hpp"
#include "inference_session.hpp"
#include "can_bus.hpp"
#include "serialization.hpp"
#include "result_conversion.hpp"
#include <opencv2/core.hpp>
#include <atomic>
@@ -60,6 +62,7 @@ struct CameraPipeline::Impl {
std::unique_ptr<DoorRisk> risk;
std::shared_ptr<const BinaryMask> doorPixels;
std::unique_ptr<Camera> camera;
std::unique_ptr<CanBus> can;
std::thread captureThread,detectorThread,inferenceThread;
mutable std::mutex stateMutex;
std::exception_ptr failure;
@@ -70,6 +73,8 @@ struct CameraPipeline::Impl {
explicit Impl(PipelineConfig c):config(std::move(c)),captures(config.queue_capacity),detections(config.queue_capacity) {
if(!config.replay_session.empty())sessionReader=std::make_unique<SessionReader>(config);
auto canConfig=config.can;if(sessionReader)canConfig.enabled=false;
can=std::make_unique<CanBus>(canConfig);
if(config.queue_capacity>8)throw std::invalid_argument("Queue capacity must be between 1 and 8");
if(config.max_people<1||config.max_people>16||!std::isfinite(config.detector_confidence)||config.detector_confidence<=0||config.detector_confidence>=1)
throw std::invalid_argument("Invalid detector configuration");
@@ -80,9 +85,11 @@ struct CameraPipeline::Impl {
if(captureThread.joinable())captureThread.join();
if(detectorThread.joinable())detectorThread.join();
if(inferenceThread.joinable())inferenceThread.join();
can->join();
}
void stop() noexcept {
stopped=true;active=false;
can->requestStop();
// Camera stays alive until all threads have joined. start()/destruction
// are owner-thread operations; requestStop() only interrupts existing work.
{std::lock_guard<std::mutex> lock(stateMutex);if(camera)camera->requestStop();}
@@ -98,6 +105,7 @@ struct CameraPipeline::Impl {
void start() {
{std::lock_guard<std::mutex> lock(stateMutex);if(started||stopped)throw std::logic_error("CameraPipeline can only be started once");started=true;}
try {
can->start();
outputWriter=std::make_unique<OutputWriter>(config.output);
sessionWriter=std::make_unique<SessionWriter>(config);
detector=std::make_unique<Detector>(config.engines/"yolo11s.engine",logger,config.detector_confidence,config.max_people);
@@ -160,6 +168,12 @@ struct CameraPipeline::Impl {
auto record=makeRecord(index,raw,isolated,fused,!config.record_session.empty(),false);
auto riskData=risk->evaluate(index,record);
auto result=std::make_shared<FrameResult>(makeFrameResult(record,riskData,detected->frame.metadata));
if(detected->frame.replay_record) {
auto const& recorded=detected->frame.replay_record->at("result");
if(recorded.contains("can"))result->can=deserializeCan(recorded.at("can"));
else result->can.status="NOT_RECORDED";
result->can.source="replay";
}else result->can=can->snapshot();
attachPoses(*result,fused);
result->image=std::move(detected->frame.image);result->door_mask_pixels=doorPixels;
result->door_mask_calibration_verified=config.door_mask_calibration_verified;
@@ -178,6 +192,17 @@ CameraPipeline::CameraPipeline(PipelineConfig config):impl_(std::make_unique<Imp
CameraPipeline::~CameraPipeline()=default;
void CameraPipeline::start(){impl_->start();}
FrameResultPtr CameraPipeline::latest()const{return impl_->results.load();}
CanSnapshot CameraPipeline::canStatus()const {
if(impl_->sessionReader) {
auto result=impl_->results.load();if(result)return result->can;
CanSnapshot s;s.source="replay";s.status="WAITING";return s;
}
return impl_->can->snapshot();
}
bool CameraPipeline::sendCan(CanFrame const& frame) {
if(impl_->sessionReader)throw std::logic_error("CAN transmission is disabled during replay");
return impl_->can->send(frame);
}
bool CameraPipeline::running()const noexcept{return impl_->active.load();}
void CameraPipeline::requestStop()noexcept{impl_->stop();}
void CameraPipeline::join(){impl_->joinWorkers();{std::lock_guard<std::mutex> lock(impl_->stateMutex);impl_->camera.reset();}impl_->rethrowFailure();}