视觉与机电作品 / 双板视觉与有限动作实验发布 内容更新

ESP32 视觉分拣实验:先过自检,再接受一次有限动作

完整双S3纸卡分拣工程:模型自检、ROI、低差值拒动、限时串口桥、ARM与独立舵机供电;50连续实物记录留空,目标参考失败保持STOP。

读完能做什么
分别验证识别、动作请求与实际落箱,保留低分、超时、误分和卡住,不让模型或过期消息越过门禁。
开始之前
完成V05模型身份/目标参考测试、V06独立外供舵机空轴与P03非阻塞状态机;会备份Flash、读电源极性与固定依赖。
所需器材
官方S3-EYE-MB_V2.2+OV2640,8MiB Flash/8MiB OPI PSRAM,原生USB数据线、官方S3-DevKitC-1 v1.1 / WROOM-1-N8R8,UART桥USB数据线、Pololu2818 FS90位置舵机;独立5.0V≥1A限流电源/正极物理开关/470µF≥10V+100nF、ARM常开按钮/10k上拉/10k信号下拉/可靠共地;架空轻纸挡片与两只纸盒、深色≤1g轻纸卡的浅色圆/方轮廓;固定照明、焦点、距离;电脑pyserial3.5
版本组合
SDK:ESP-IDF5.5.5 b774170… / Python3.12.13 / GCC14.2.0视觉:ESP-DL3.3.8 / camera2.1.8 / dl_fft0.8.0 / esp_jpeg1.3.1 / esp_new_jpeg1.0.2模型:V05原7296B / c495b5de… / int8 1×16×16×1指数−7主机与机构:pyserial3.5 / ASCII协议v1 / Pololu2818 FS90-C V1.0 / PWM50Hz14bit
适用范围

原ID V10/M6;可信本地双串口、轻纸卡手动送料;未测真实视觉/波形/机构/50样本,实际QEMU参考FAILED/STOP,禁止绕过目标自检。

这篇验证到了哪一步

资料核对已通过
docs/esp32-evidence/vision-sorter.md对象:固定板图/FS90-C/API/模型身份版本:IDF5.5.5 / ESP-DL3.3.8 / camera2.1.8验证日期:
构建 / 配置已通过
docs/esp32-evidence/vision-sorter-builds.json对象:EYE native + UART诊断 / DevKit UART0版本:IDF5.5.5验证日期:
仿真未通过
docs/esp32-evidence/vision-sorter-qemu.json对象:真实UART镜像参考FAIL→STOP/0RESULT;桌面策略/PTY另记验证日期:
本站实板待验证
examples/esp32/esp32-vision-sorter-project/observations对象:相机域/波形/方向/50连续轻纸卡/误分/卡住均未执行

构建通过只说明指定环境中的代码或配置通过检查;实物功能、功耗和稳定性以对应的实板记录为准。

01 / 双板视觉与有限动作实验

先把作品拆成识别、请求与真实落箱三层

本实验仅处理称重≤1g的轻纸卡:S3-EYE识别固定深底浅色圆/方轮廓,电脑桥发出一次有限舵机请求,DevKit带动架空小纸挡片把手动放下的一张卡导向A/B盒。没有自动送料、位置、落箱或卡住传感器;预测正确、ACK接受与真实落箱分别记,不能互相替代。

本站已完成三配置构建、生产同源策略、真实OS双PTY桥和原模型目标自检诊断。当前实际S3 QEMU参考仍失败、STOP且0预测;实板全空。完整工程提供从停止门禁到实物验收的路径,未通过模型参考自检不得带真实舵机继续,也不能拿128个合成CPU成绩冒充相机准确率。

参考:[1] ESP-DL3.3.8 Model::test / run / tensor入口[2] ESP-DL3.3.8 实际参考比较实现[7] 官方S3-EYE固定修订指南[10] Pololu2818 FS90位置舵机与3.3V信号

02 / 双板视觉与有限动作实验

锁定两块不同的S3板,不能把同号GPIO接错板

视觉板只限官方ESP32-S3-EYE-MB_V2.2+OV2640,8MiB Flash/DIO80与8MiB OPI PSRAM80,原生Micro-USB Serial/JTAG19/20;没有USB-UART桥。GPIO3不配置,LCD/SD/麦克风/RF不初始化。SCCB4/5、VSYNC6、HREF7、PCLK13、XCLK15,D0..7为11/9/8/10/12/18/17/16,完整配置在下载工程。

动作板是官方ESP32-S3-DevKitC-1 v1.1/WROOM-1-N8R8,PSRAM/PM关闭,电脑连接UART桥口(UART0 43/44,115200)。GPIO5/6仅属于这块动作板;EYE的5/6已连接相机。严禁将actuator固件刷入EYE,GPIO6与OV2640 VSYNC网冲突;刷写前按板壳标签核对工程/真实端口,刷错先断电进入ROM恢复。两板之间无GPIO线和5V/3V3线,分别由电脑USB供电,电脑运行本地可信双串口桥。

器材唯一范围
位置舵机Pololu2818 / FEETECH FS90 / FS90-C V1.0;不是FS90R
外供独立5.0V额定≥1A,限流1A,正极物理断电开关
标记卡深色轻纸卡上浅色圆/方轮廓;固定纸材/照明/距离/焦点,≤1g
开发环境IDF5.5.5、Python3.12.13、GCC14.2.0;pyserial3.5

参考:[4] esp32-camera2.1.8 帧/归还/时间戳API[7] 官方S3-EYE固定修订指南[8] S3-EYE MB2.2实际原理图[9] DevKitC-1 v1.1 固定引脚/供电指南

03 / 双板视觉与有限动作实验

先断电接线与空轴,外供正极不进开发板

DevKit GPIO5/J1-5接常开ARM按钮到GND,并另10k上拉到本板3V3/J1-2;GPIO6/J1-6接FS90信号,并另10k下拉GND。外供正极经物理开关仅到FS90红线,棕/黑线直接回外供负极,DevKit GND/J1-22低阻共地;470µF≥10V电解并100nF放在舵机旁,注意极性。不要让电机回流经过开发板供电轨,不并两板5V/3V3正极。

产品页明确FS90支持3.3V信号。原厂手册列900–2100µs范围、700mA@4.8V/800mA@6V堵转电流;Pololu600mA@6V为其测值且可变。本实验5V≥1A/限流1A是设计规格,不是本站测得5V堵转电流。先拔连杆空轴试1500/1400/1600,初次1500可能跳动,确认无硬限位再断电装极轻挡片;不要手堵轴,不把A/B请求直接当实际方向。

参考:[9] DevKitC-1 v1.1 固定引脚/供电指南[10] Pololu2818 FS90位置舵机与3.3V信号[11] FS90-C V1.0原厂规格/电流/死区[12] Pololu规格值来源区别[13] IDF5.5.5 LEDC duty/update/stop

04 / 双板视觉与有限动作实验

固定依赖、模型身份与三种构建上下文

IDF5.5.5/b774170…;ESP-DL3.3.8/77a8a624…、dl_fft0.8.0、esp32-camera2.1.8/b0556a78…、esp_jpeg1.3.1、esp_new_jpeg1.0.2,标准Registry配置与dependencies.lock随包提供。本站仅克隆同版本已装缓存,不改SDK/组件源码。

camera/main/shape-s3.espdl沿用V05原7296B/c495b5de…模型;CMake对完整SHA检查,更换模型被拒绝。model-reference包含原训练结果、版本和训练源码供追溯,不重训、不把打印模板称新训练集。三最终配置分别是EYE原生USB、同源UART诊断、DevKit桥UART0;UART诊断仅供QEMU,不表示EYE存在UART桥,勿接占用LCD的43/44。首次缩进警告Exit2与后续成功都保留,编译不等于运行或机械成功。

  1. 备份原Flash/分区并安装固定IDF5.5.5环境。
  2. 在camera内执行idf.py set-target esp32s3、idf.py build,使用EYE原生USB刷写/监视;确认参考测试和PSRAM,退出monitor。
  3. 在actuator内以同SDK构建,用DevKit UART桥刷写/监视;先断舵机外供检查默认LOW与ARM。
  4. 诊断UART使用单独build-uart和独立sdkconfig,完整命令见README;不得沿用原生USB sdkconfig冒称切换成功。
代码 / 配置
# ---- camera/main/idf_component.yml ----
dependencies:
  idf: "==5.5.5"
  espressif/esp-dl: "==3.3.8"
  espressif/dl_fft: "==0.8.0"
  espressif/esp32-camera: "==2.1.8"
  espressif/esp_jpeg: "==1.3.1"
  espressif/esp_new_jpeg: "==1.0.2"

参考:[1] ESP-DL3.3.8 Model::test / run / tensor入口[3] ESP-DL3.3.8 TensorBase与指数[4] esp32-camera2.1.8 帧/归还/时间戳API[7] 官方S3-EYE固定修订指南[9] DevKitC-1 v1.1 固定引脚/供电指南

05 / 双板视觉与有限动作实验

模型test失败就STOP,中央ROI也要同分布

启动先检查8MiB PSRAM,再实际model->test。参考失败直接STOP,不初始化相机、不产生CAMERA_READY/RESULT。输入必须INT8/NHWC[1,16,16,1]/标量指数−7,输出INT8[1,2]/标量指数−32..16;形状、dtype或逐通道指数不符同样停止。不存在skip-test、人工分数或手动COMMIT的正式桥选项。

OV2640灰度160×120取中央64×64(x48..111/y28..91),每4像素取中心点缩到16×16,pixel/255后按指数−7四舍五入并饱和127。固定训练背景15..44、浅色轮廓185..245;白底黑线或实心图形不等价。本包打印深底浅轮廓只是摆位帮助,先用V01照片固定完整轮廓在ROI内约占一半到三分之二,回刷V10后再测。镜头曝光、纸纹、旋转、阴影仍是未证明的域差异。

参考:[1] ESP-DL3.3.8 Model::test / run / tensor入口[2] ESP-DL3.3.8 实际参考比较实现[3] ESP-DL3.3.8 TensorBase与指数[4] esp32-camera2.1.8 帧/归还/时间戳API[6] esp32-camera2.1.8 OV2640灰度格式

06 / 双板视觉与有限动作实验

把低置信拒动写成可检查的logit差值

输出是两个int8量化logits和标量指数e,不做softmax。主机计算abs(raw0−raw1)×2^e;相等或差值<2.0发CANCEL,满足门限才取较大者:circle=0→A,square=1→B。raw越界、指数越界或非规范整数不是有效预测。

2.0是本实验固定的未校准拒动门限,不能称概率、百分比置信度或准确率保证;大差值也可能错。固定门限后才做连续50个实体尝试,不能看错误后在同run改阈值并删除坏行。生产像素与门限头直接用于同源桌面检查。

代码 / 配置
// ---- shared/decision.h ----
/* SPDX-License-Identifier: MIT */
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <math.h>
namespace v10 {
/* Uncalibrated logit margin, not a probability or camera accuracy claim. */
inline int decide(int a,int b,int exponent){if(a < -128||a>127||b < -128||b>127||exponent < -32||exponent>16)return -1;double gap=ldexp((double)(a>b?a-b:b-a),exponent);if(a==b||gap<2.0)return -1;return b>a?1:0;}
/* Central64x64 nearest-neighbour to16x16. No histogram/contrast correction. */
inline bool pixels(const uint8_t*src,size_t len,unsigned w,unsigned h,int8_t*out){if(!src||!out||w!=160||h!=120||len!=19200)return false;for(unsigned y=0;y<16;y++)for(unsigned x=0;x<16;x++){unsigned p=src[(28+y*4+2)*160+(48+x*4+2)];unsigned q=(p*128U+127U)/255U;out[y*16+x]=(int8_t)(q>127?127:q);}return true;}
}

参考:[1] ESP-DL3.3.8 Model::test / run / tensor入口[3] ESP-DL3.3.8 TensorBase与指数

07 / 双板视觉与有限动作实验

帧、主机与动作板各自计时,不做跨板相减

固定驱动用本板esp_timer_get_time在DMA帧启动时写fb.timestamp,属于启动近似而不是精确曝光时刻。CAPTURE解析后只接受本机请求之后、非未来且帧龄≤500ms的帧;最多取四次,每个非空帧恰一次return,归还后再推理,推理后复核总耗时≤1.5s与帧龄。fb_get可阻塞更久,这些检查不保证硬实时返回。

主机只以自己的monotonic等待关联RESULT≤1.6s,已排队消息>200ms拒绝;动作板以自己的64位微秒钟检挑战至COMMIT≤2s、距本板最后收到当前SESSION/PING>300ms撤会话(重复同会话PING也刷新,不从物理拔线瞬间计时),owner回拨/间隔>250ms恢复运行时撤销。没有servo_now减eye_timestamp。即使相机或电脑阻塞,过期token也不能在数分钟或完整32位周期后复活。

参考:[4] esp32-camera2.1.8 帧/归还/时间戳API[5] esp32-camera2.1.8 DMA帧启动时间戳[14] IDF5.5.5 UART非阻塞FIFO发送[15] IDF5.5.5 USB Serial/JTAG驱动[16] IDF5.5.5 64位单调微秒计时

08 / 双板视觉与有限动作实验

一次性请求、整批失效预检与可信本地边界

ASCII协议带版本1、boot/session/strictseq/一次性token和CRC16-CCITT-FALSE,完整规范见README。桥先观察实际CAMERA_READY再建动作SESSION;需要新的REQUEST/token,才向当前camera boot请求新帧。重复COMMIT不叠加运动,旧会话/过期/错误token拒绝。随机标识与CRC不是密码学认证,仅用于本机可信双串口,不对远程开放。

主机Bridge.wait响应等待阶段每次读取两端完整批次,先通查STOP、boot变化、过期和非预期REJECT,再选择匹配结果;保留原RESULT后新boot仍发COMMIT的反例及修正。迟到旧行也可能保守停止,不承诺自动忽略所有旧消息继续。ACK阶段才观察到失效时COMMIT可能已经在飞或接受,不能瞬间撤回;ACK只表示状态机接受,不是波形/位置/落箱。非法/溢出行丢弃直到真实LF;部分行空闲>200ms也持续丢尾到LF,不能把旧后缀接成新命令。idle只检查STOP、READY的boot变化和视觉READY间隔,不把wait的所有校验覆盖到任意op。

参考:[14] IDF5.5.5 UART非阻塞FIFO发送[15] IDF5.5.5 USB Serial/JTAG驱动[16] IDF5.5.5 64位单调微秒计时

09 / 双板视觉与有限动作实验

ARM、有限脉宽与CPU停调度的真实边界

新SESSION后必须先松开ARM稳定50ms,再新按住1s;启动按住不武装,每轮消费后重来。动作第一秒请求1500µs,随后每100ms至多5µs到1400(A)/1600(B),约3–4s保持路由,再回1500,总6s停止PWM。50Hz/14bit的三个duty为1147/1229/1311;约1.22µs量化和10µs原厂死区意味着5µs命令步进不等于平滑物理转动。

原始ARM松开在下次owner采样停止,不等释放消抖。只有一个owner操作LEDC;API故障锁存、撤会话时尽力发STOP,停止PWM不依赖串口送达。信号LOW不是断5V、刹车、到位或回中证明;CPU完全停调度时LEDC可维持旧波形,恢复后才能检查250ms间隔。必须保留外供正极物理开关,出现顶住/异响/发热先断电再清卡,不能靠串口心跳当硬件急停。

代码 / 配置
// ---- actuator/main/main.cpp ----
/* SPDX-License-Identifier: MIT */
#include <cstdio>
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "esp_timer.h"
#include "esp_random.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "actuator.h"
#include "transport.h"
static uint64_t nonce(){uint64_t n;do{n=((uint64_t)esp_random()<<32)|esp_random();}while(!n);return n;}
static esp_err_t apply(bool active,uint16_t pulse){if(!active)return ledc_stop(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0,0);esp_err_t e=ledc_set_duty(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0,v10::duty(pulse));return e==ESP_OK?ledc_update_duty(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0):e;}
extern "C" void app_main(){
 gpio_config_t in={};in.pin_bit_mask=1ULL<<GPIO_NUM_5;in.mode=GPIO_MODE_INPUT;ESP_ERROR_CHECK(gpio_config(&in));
 ledc_timer_config_t t={};t.speed_mode=LEDC_LOW_SPEED_MODE;t.duty_resolution=LEDC_TIMER_14_BIT;t.timer_num=LEDC_TIMER_0;t.freq_hz=50;t.clk_cfg=LEDC_USE_APB_CLK;ESP_ERROR_CHECK(ledc_timer_config(&t));
 ledc_channel_config_t c={};c.gpio_num=GPIO_NUM_6;c.speed_mode=LEDC_LOW_SPEED_MODE;c.channel=LEDC_CHANNEL_0;c.timer_sel=LEDC_TIMER_0;c.duty=0;c.hpoint=0;ESP_ERROR_CHECK(ledc_channel_config(&c));ESP_ERROR_CHECK(apply(false,1500));
 printf("V10 FS90 POSITION SERVO ONLY; external5V; signal is not power removal. No encoder/jam sensor. UART0 bridge115200.\n");
 if(v10::transport_init()!=ESP_OK)return;
 v10::Actuator s(nonce());v10::Lines lines;v10::Tx tx;bool was=false,fault_reported=false;uint16_t prior=0;uint64_t prior_session=0;
 for(;;){
  uint64_t now=(uint64_t)esp_timer_get_time();s.tick(gpio_get_level(GPIO_NUM_5)==0,now);
  if(lines.expire(now))s.revoke(10);
  char input[64];int n=v10::read_bytes(input,sizeof input);if(n<0)s.api_fault();
  for(int k=0;k<n;k++){v10::Msg m;int rc=lines.feed(input[k],m,(uint64_t)esp_timer_get_time());if(rc<0)s.revoke(10);else if(rc>0){
    /* Resample raw ARM and deadlines at every command, not a stale loop sample. */
    now=(uint64_t)esp_timer_get_time();s.tick(gpio_get_level(GPIO_NUM_5)==0,now);
    auto answer=s.receive(m,now,nonce());if(!tx.queue(answer))s.api_fault();
  }}
  /* Stop/heartbeat also checked after parsing. No other task owns this channel. */
  s.tick(gpio_get_level(GPIO_NUM_5)==0,(uint64_t)esp_timer_get_time());
  if(s.active!=was||(s.active&&s.pulse!=prior)){if(apply(s.active,s.pulse)!=ESP_OK){s.api_fault();(void)apply(false,1500);}was=s.active;prior=s.pulse;}
  /* Explicit STOP is already known to the bridge; no unsolicited echo may
     poison its next SESSION. Local timeout/parse/gap/API faults still report. */
  if((prior_session&&!s.session&&s.reason!=7)||(s.fault&&!fault_reported)){
   if(!tx.queue({v10::STOP,s.boot,0,0,0,(int)s.reason,0,0}))s.api_fault();
   fault_reported=s.fault;
  }
  prior_session=s.session;
  if(!tx.poll())s.api_fault();
  if(s.fault){(void)apply(false,1500); /* sticky RESET-only API fault */}
  vTaskDelay(pdMS_TO_TICKS(10));
 }
}

参考:[10] Pololu2818 FS90位置舵机与3.3V信号[11] FS90-C V1.0原厂规格/电流/死区[13] IDF5.5.5 LEDC duty/update/stop[14] IDF5.5.5 UART非阻塞FIFO发送[16] IDF5.5.5 64位单调微秒计时

10 / 双板视觉与有限动作实验

按层运行,再记录50个连续尝试

先不接舵机外供完成模型与镜头层,失败停此;再按V06空轴完成电源/波形/ARM层,确认实际A/B方向;最后断电装纸挡片并以每次一张、架空轻纸卡整合。不是自动送料:识别时纸卡在独立托盘,收到请求后只有目视确认挡片方向且手离开行程,才在约3–4s保持窗手动放开一张卡;来不及就跳过并记录,不追卡或伸手。

安装pyserial3.5,退出monitor,执行tools/bridge.py --camera实际EYE端口 --actuator实际DevKit桥端口 --output run50.csv。固定奇数circle/偶数square,25/25交错,输入truth确认才发新请求。低分放人工复核盒;高分也逐项填observed_bin、jam、recovery、note。每轮STOP并重新会话/ARM;错误或jam记录落盘后结束run,诊断后另起文件,部分run与journal必须保留。

CSV与.events.jsonl排他创建、每事件flush+fsync,不能覆盖/补造;观察不完整时journal仍留attempt_begin/result。analyze_run.py要求顺序1..50与固定truth,少于50仅报告计数,不给准确率;全部50包含reject、unavailable、误分、卡住和错误。endToEndOver50同时要求预测/请求/真实落箱正确且无jam/error,分母恒50。工具只能分析操作者输入,不能认证其物理真实性。所有中断run也要与完整50run并列报告attempt/jam/error与中断原因,不能只挑完整run或把其比例当全部尝试总体表现;部分run不补造、不删除。

代码 / 配置
# ---- tools/analyze_run.py ----
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
"""All50 attempts remain denominator. Partial runs have no accuracy claims."""
import argparse,csv,json,math
FIELDS=['sample','truth','prediction','raw0','raw1','exponent','margin','command','observed_bin','jam','error','recovery','camera_boot','actuator_boot','session','physical_observer_note']
def analyze(path):
    with open(path,newline='')as f:
        reader=csv.DictReader(f)
        if reader.fieldnames!=FIELDS:raise ValueError('schema mismatch')
        rows=list(reader)
    if len(rows)>50:raise ValueError('at most50')
    for n,r in enumerate(rows,1):
        if r['sample']!=str(n):raise ValueError('continuous sample1..N required; no delete/reorder')
        if r['truth']!=('circle'if n%2 else 'square'):raise ValueError('preassigned odd circle/even square')
        if r['prediction']not in ['circle','square','reject','unavailable']or r['command']not in ['routeA','routeB','none','none_or_unconfirmed']:raise ValueError('result vocabulary')
        if r['observed_bin']not in ['A','B','review','unknown']or r['jam']not in ['yes','no']:raise ValueError('physical observation required')
        if any(not r[x]for x in ['recovery','physical_observer_note','camera_boot','actuator_boot','session']):raise ValueError('missing provenance/observation')
        if r['prediction']in ['circle','square','reject']:
            raw=[int(r[k])for k in ['raw0','raw1','exponent']]
            if any(str(v)!=r[k]for v,k in zip(raw,['raw0','raw1','exponent']))or not(-128<=raw[0]<=127 and -128<=raw[1]<=127 and -32<=raw[2]<=16):raise ValueError('score contract')
            gap=math.ldexp(abs(raw[0]-raw[1]),raw[2]);margin=float(r['margin'])
            pred='reject'if raw[0]==raw[1]or gap<2.0 else('square'if raw[1]>raw[0]else'circle')
            if not math.isfinite(margin)or margin!=gap or pred!=r['prediction']:raise ValueError('prediction/margin inconsistent with raw logits')
            command='none'if pred=='reject'else('routeA'if pred=='circle'else'routeB')
            if r['command']!=command:raise ValueError('command inconsistent with prediction')
        elif not r['error']:raise ValueError('unavailable needs recorded error')
    complete=len(rows)==50
    correct=sum(r['prediction']==r['truth']for r in rows)
    routed=sum(r['command']in ['routeA','routeB']for r in rows)
    end_to_end=sum(r['prediction']==r['truth']and r['command']==('routeA'if r['truth']=='circle'else'routeB')and r['observed_bin']==('A'if r['truth']=='circle'else'B')and r['jam']=='no'and not r['error']for r in rows)
    return {'attempts':len(rows),'qualified50':complete,'requestedRoutes':routed,'rejectedOrUnavailable':sum(r['prediction']in ['reject','unavailable']for r in rows),'jamRows':sum(r['jam']=='yes'for r in rows),'errorRows':sum(bool(r['error'])for r in rows),'predictionCorrectOver50':correct/50 if complete else None,'endToEndOver50':end_to_end/50 if complete else None,'scope':'Only supplied operator CSV; does not authenticate physical origin, infer confidence calibration or detect unreported jams.'}
def main():
    p=argparse.ArgumentParser(description=__doc__);p.add_argument('csv');a=p.parse_args()
    try:print(json.dumps(analyze(a.csv),indent=2))
    except (ValueError,OSError)as e:p.exit(2,str(e)+'\n')
if __name__=='__main__':main()

参考:[7] 官方S3-EYE固定修订指南[10] Pololu2818 FS90位置舵机与3.3V信号[13] IDF5.5.5 LEDC duty/update/stop[16] IDF5.5.5 64位单调微秒计时

11 / 双板视觉与有限动作实验

桌面夹具、当前QEMU失败与未实测表分开

生产wire/decision/actuator头的335条ASan/UBSan断言覆盖规范整数、CRC、旧尾、像素、门限、重放、时限、ARM、长运行与PWM请求;完整Bridge.trial/wait的18组批次覆盖RESULT/ACK前后失效与过期/错token/串口错误。双真实OS PTY走生产Port/Bridge、生产策略actorpeer和明确camera桩,六场景及空闲旧尾均通过;这些都不是模型推理、USB电气或物理分拣。

本次同一真实UART镜像在S3 QEMU仍参考28与−128不匹配,ESP_FAIL→V10 STOP,不进入相机初始化、0RESULT。simulation保持failed;不能将构建和受控成功分数测试改成相机已成功。observations的连续50、电源波形、相机层、故障表全部仅表头,真实镜头表现、50连续成功率、方向、电流、动作耗时与卡住恢复仍待现场执行。

做到这里,你应该看到
固定模型参考必须先在目标通过;再做相机域与机构层。当前软件完整交付不等于实物分拣通过。

参考:[1] ESP-DL3.3.8 Model::test / run / tensor入口[2] ESP-DL3.3.8 实际参考比较实现[4] esp32-camera2.1.8 帧/归还/时间戳API[5] esp32-camera2.1.8 DMA帧启动时间戳[13] IDF5.5.5 LEDC duty/update/stop

12 / 双板视觉与有限动作实验

故障恢复以旧证据与新会话为起点

参考FAIL先保持舵机外供断开,查完整模型SHA/PSRAM/运行库与V05逐层诊断;不要绕过test。相机初始化失败断电检查板修订/原装排线。低分或错分留样本/光照/raw值,不能在同run偷偷改阈值。CRC、boot变化、串口错、pending过期先松ARM/断外供,保CSV+journal;退出桥,诊断并RESET两板后重新启动新run。

API故障须诊断后RESET,继续PING不能清锁存。纸挡片顶住、卡片卡住或掉错先物理断舵机正极,再移卡并写明jam/误分/恢复。程序没有传感器证明卡已清除,GPIO信号LOW也不证明轴停止。完成本项目后可用E10把固定编译、策略和桥接拒动测试纳入后续维护,所有物理结果继续独立留原始记录。

如果卡住了
模型STOP、物理异响或无法确认的运动都先停止本轮;保留部分run及失败,不补成50成功。

参考:[1] ESP-DL3.3.8 Model::test / run / tensor入口[10] Pololu2818 FS90位置舵机与3.3V信号[11] FS90-C V1.0原厂规格/电流/死区[13] IDF5.5.5 LEDC duty/update/stop[14] IDF5.5.5 UART非阻塞FIFO发送

BACK TO THE SOURCE

资料来源与版本说明

固定板图、FS90原厂规格与实际安装API逐项核对;构建、受控主机夹具、QEMU失败与空物理记录分开,不把软件接受命令称已完成分拣。资料核对日期:。资料核对、程序构建与实板测试分别记录,不互相替代。

  1. ESP-DL3.3.8 Model::test / run / tensor入口
  2. ESP-DL3.3.8 实际参考比较实现
  3. ESP-DL3.3.8 TensorBase与指数
  4. esp32-camera2.1.8 帧/归还/时间戳API
  5. esp32-camera2.1.8 DMA帧启动时间戳
  6. esp32-camera2.1.8 OV2640灰度格式
  7. 官方S3-EYE固定修订指南
  8. S3-EYE MB2.2实际原理图
  9. DevKitC-1 v1.1 固定引脚/供电指南
  10. Pololu2818 FS90位置舵机与3.3V信号
  11. FS90-C V1.0原厂规格/电流/死区
  12. Pololu规格值来源区别
  13. IDF5.5.5 LEDC duty/update/stop
  14. IDF5.5.5 UART非阻塞FIFO发送
  15. IDF5.5.5 USB Serial/JTAG驱动
  16. IDF5.5.5 64位单调微秒计时