视觉与机电作品 / 机电控制与分层验收发布 内容更新

ESP32控制舵机:把脉宽、动力电源和真实角度分开

用指定FS90与独立5V电源建立空载舵机台,限定1400..1600µs命令、保持使能和10秒窗口,再分层检查波形、供电与实际位置。

读完能做什么
用指定FS90与独立5V电源建立空载舵机台,限定1400..1600µs命令、保持使能和10秒窗口,再分层检查波形、供电与实际位置。
开始之前
先完成列出的计时/工程/排错基础,能辨认自己的板修订、低压电源与仪表地参考,再在空载架台操作。
所需器材
官方S3 DevKitC-1 v1.1 N8R8与桥USB数据线、独立稳压5V/≥1A实验电源、低压总开关与合适波形/电流仪表、10kΩ电阻、100nF陶瓷、470µF≥10V极性电容、可靠焊接/绝缘短线、固定架、Pololu2818 FEETECHFS90,未装负载摆臂,ARM常开按钮
版本组合
框架:ESP-IDF5.5.5 / b774170ff46c393eeb5e495ea37936038d3f4f4f工具:Python3.12.13 / GCC14.2.0 esp-14.2.0_20260121板与配置:DevKitC1 v1.1 N8R8 / DIO8MiB80MHz / PSRAMoff / PMoff
适用范围

仅官方S3 DevKitC1 v1.1 N8R8 / IDF5.5.5;8MiB DIO80/PSRAM关闭/PM关闭。Pololu2818FS90,独立5.0V与空轴。全部电气、波形、电流、机械位置/转速/停止与复位结果pending。

这篇验证到了哪一步

资料核对已通过
docs/esp32-evidence/actuators-sources.json 与 actuators.md,固定源/原厂PDF及具体矛盾注记。验证日期:
构建 / 配置已通过
docs/esp32-evidence/actuators-builds.json:实际完整IDF编译、前后输入及bin/ELF/map/配置/原logSHA。对象:esp32s3 /8MiB/noPSRAM/noPM版本:ESP-IDF5.5.5验证日期:
仿真已通过
docs/esp32-evidence/actuators-host.json:8组合成策略;不模拟驱动、电机或供电。对象:macOS arm64 same-source ASan/UBSan验证日期:
本站实板待验证
没有指定执行器、电源、波形/电流或运动实测,observations.csv仅表头,所有实际现象仍待台架执行。

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

01 / 机电控制与分层验收

先把命令和实际完成分开

这份完整例程用实体保持按钮启动一个有限时间、有限脉宽的空载实验。它输出位置请求,不读取舵机真实角度;“命令1500µs”不等于“轴已在90°”。原计划的角度限制在本例落实为1400..1600µs保守命令窗口,实物位置须另量。

参考:[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

02 / 机电控制与分层验收

指定部件与供电

舵机固定Pololu #2818 FEETECH FS90(位置型,不是FS90R连续旋转型),其商品页所链接厂家FS90-C V1.0手册900..2100µs/1500µs中点;我们不扩展到机械极限。供货标签/修订先与该资料核对,匿名SG90不能直接套同一电流/角度结论。商品页明确支持3.3V控制信号,不从“能插三根线”推断所有舵机都支持。

用独立稳压5.0V实验电源,额定至少1A,先设电流限制1A,带可立即断开的低压开关。板只由桥USB供电,外部5V绝不连板的5V/3V3;电源负极、舵机GND与板GND在低阻公共地相连,舵机大电流回路直接回电源,别绕过面包板主控细线。电源应能应对启动瞬态,1A是本例设定,不是保证每台舵机都满足。靠近舵机供电口并联470µF/≥10V极性电容和100nF陶瓷,核正负极;电容不能替代合格电源/导线,改线前断电并等电容放电。

厂商链接手册的4.8V/6V堵转栏是700/800mA;Pololu商品spec页自己的6V测试值600mA并说明不是厂家定值。二者不一致,不能挑600mA当所有批次上限。本例按独立≥1A台架留余量并记录实际启动电流;不手抓堵转来复现规格,也不把6V参数直接当5V实测。

先不装摆臂/负载,把舵机外壳固定,轴周围留空。核供应方此台JR接头的端点图,再追三根线;资料不足先不要加电。首次中点命令可能使轴突然到中点附近,启动无PWM也不保证轴原位/无抖动。断PWM仅撤控制信号,舵机电源仍在;放松、保持或残余动作由实物决定。

端点连接约束
GPIO5/J1-5常开ARM按钮到GND;同点外接10k到本板3V3LOW保持,初始必须松开
GPIO6/J1-6舵机signal,另10k到GND3.3V信号;用明确GND/V+/signal端点,不凭线色猜
外部5.0V+舵机V+,电容正端不接主控板电源脚
外部电源负极舵机GND、电容负端、板GND/J1-22电机回流直接回电源;信号有共同参考
桥USB主控供电、下载、UART0外部执行器电源开关独立可断

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

03 / 机电控制与分层验收

程序怎样限制命令

50Hz/20ms周期,14bit分辨率;duty=round(pulse_us×16384/20000)。1400/1500/1600µs对应1147/1229/1311,单步名义量化约1.22µs。这是计算与SDK请求值,真实周期/高脉宽用示波器或逻辑分析仪检查;看占空比7.5%时也别忽略周期必须是本例20ms。

上电默认ledc_stop→LOW,GPIO6的外部10k下拉在ROM/重启阶段也给控制线明确低电平。ARM启动就按住不会开始;松开稳定50ms后,再按住稳定并保持1秒才能启动。先请求1500µs并留1秒,再每100ms最多改变5µs,在1400..1600间缓慢往返;不跳过迟到时刻连补多步。持续保持最多10秒,到时停PWM并要求松开重来。厂家名义死区10µs大于本例5µs命令步进,真实轴可能隔几步才动或存在滞回;慢改命令不保证机械连续平滑。

原始ARM一旦释放,下一次owner tick就请求停PWM,不必等释放去抖;重新ARM仍须稳定释放/按下条件。主循环请求20ms tick,不将它叫严格20ms响应保证。时钟倒退或相邻owner运行间隔>250ms会撤本地使能,实际停信号发生在owner恢复执行时;不能保证卡死时自动切断动力。API错误锁闭至手工重启,先请求LOW,保留错误日志。

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

04 / 机电控制与分层验收

台架步骤和通过条件

observations.csv有command与measured分列。要诊断抖动,同步看signal脉宽/周期与servo V+/主控3V3最小值,再查共地、接头/线阻和电源限流,最后才改软件。分辨率加到20bit不能补足缺电;把微秒直接当角度也不能校准零点。

  1. 执行器外电源关闭、ARM松开,只USB刷写。先不接舵机signal,在GPIO6/GND测上电默认LOW;再保持ARM检查50Hz及中点/窗口脉宽、释放时软件停信号。自己实际通过后才断电接舵机。
  2. 核三线与共地,外电源5V/1A限制,上电仍不按ARM,观察无请求状态;此前无反馈、任何抖动都记录,不补写“默认安全角度”。
  3. 外壳固定、轴空载。保持ARM,记录中点请求、真实初动、电源最小值/电流与板3V3;再观察慢扫窗口并对照串口命令,不把日志数值当真实角度。
  4. 松开ARM,分别检查控制线LOW、轴实际何时停止/是否放松;保持超过10秒检查软件期限。上电按住、快速抖动、RESET后需重新释放也单独记录。
  5. 只有这些空载检查通过,才在完全断电后安装轻小摆臂,重新检查机械余量;不顶住端点、不连接承重或夹持机构。结束先松按钮确认信号停,再断执行器电源和USB。

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

05 / 机电控制与分层验收

故障定位与恢复

实际本轮app205488B、8组同源主机检查通过;未连接舵机或示波器,没有实际角度、抖动、电压、电流或上电默认位置结果。保留所有待测行。

现象先证据恢复
构建成功不动ARM先释放、持有1秒、signal波形、执行器5V和接头端点先断外电源查线,勿一口气放宽脉宽
有PWM却抖动/复位同步供电跌落、地线、电流限制、接头和机械阻力卸负载、修电源;保留reset reason,勿关闭brownout
初次ARM大幅动作实际初始轴位与1500µs响应先空轴,停机断电调整机械;不宣称自动归零已验证
停PWM后轴仍动/松实际signalLOW与动力仍在这是撤信号,不是制动/电源隔离;按台架开关断外电源
STOP_REASON3/API_FAULTowner时序/串口阻塞/错误码停机保存日志,排查后松按钮再重启

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

06 / 机电控制与分层验收

固定工程、构建与恢复

只支持官方ESP32-S3-DevKitC-1 v1.1 / ESP32-S3-WROOM-1-N8R8,ESP-IDF5.5.5(commit b774170ff46c393eeb5e495ea37936038d3f4f4f),8MiB DIO80MHz/PSRAM关闭,PM关闭,UART0桥口115200。GPIO19/20原生USB与OPI专用脚未用于外设。实际工具Python3.12.13、GCC14.2.0 esp-14.2.0_20260121;无额外managed组件,不需要安装另一个SDK。

激活自己安装的固定IDF环境,进入解压工程根,使用新的配置目录:

REPLACE_PORT换成本板桥接串口。已有sdkconfig优先于defaults;复用旧配置时要核target/8MB/DIO/PSRAM=n/PM=n及实际UART。串口退出Ctrl+]。BOOT+RESET经桥口恢复ROM下载,先断执行器外部电源、松开全部按钮,再刷回已保存的正常固件,不改eFuse、不盲擦Flash。没有实板上传、运动、波形、电流或故障复位记录。

代码 / 配置
idf.py -B build-local -D SDKCONFIG=build-local/sdkconfig build
idf.py -B build-local -D SDKCONFIG=build-local/sdkconfig -p REPLACE_PORT flash monitor

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

07 / 机电控制与分层验收

纯逻辑与真实物理分开

host_check.c直接包含生产策略头,在macOS arm64以clang ASan/UBSan执行合成按键和64位时刻;它不模拟LEDC、GPIO、电机/舵机、惯量或电源。读者可执行:

主循环有自己的单写者,不使用硬件fade,因此用ledc_set_duty再ledc_update_duty;固定5.5.5的ledc_set_duty_and_update会要求fade服务已安装,不能不读前置条件就替换。ledc_stop把该通道输出停在LOW;下一次set+update会重新使能信号,这是固定源码事实,不是示波器结果。APB时钟与PM关闭保证配置的时钟前提,不保证实物抖动、电源或机械响应。软件只在owner实际运行时检查时间;任务阻塞/CPU挂死期间PWM硬件可能继续输出,不能把250ms迟到检查或软件看门狗当独立硬件急停。

每份observations.csv只有表头。自己台架必须保留板号/模块修订、完整源与镜像SHA、接线照片、供电设定及真实波形/现象/失败行。名义频率、量化误差和主机模型不是本站运动、电流、温升或电源稳定性数据。

代码 / 配置
cc -std=c11 -Wall -Wextra -Werror -fsanitize=address,undefined -fno-omit-frame-pointer host_check.c -o /tmp/actuator-host
/tmp/actuator-host

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

08 / 机电控制与分层验收

许可和上游

应用、策略头、主机夹具、图文为本站原创MIT,见LICENSE;SDK按其原许可证,未打包SDK或编译产物。固定源码依据ESP-IDF5.5.5 components/esp_driver_ledc/include/driver/ledc.h、src/ledc.c、gpio.h及esp_timer.h;板卡依据官方v1.1固定指南。完整上游链接和器件资料范围见THIRD_PARTY.md/versions.json。

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项[6] Pololu2818 FS90:位置型、3.3V信号与脉宽范围[7] 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区[8] Pololu伺服控制接口:脉宽而非占空比决定请求[9] Pololu独立测试电流及非厂家定值注记

09 / 机电控制与分层验收

实际构建的完整主程序与共享策略

下面两个文件与完整下载工程逐字对应。LEDC/GPIO由单个owner使用,策略头也直接供主机夹具调用;文件名注释只是分隔,不在构建时拼成一个文件。

代码 / 配置
// ---- main/main.c ----
/* SPDX-License-Identifier: MIT */
#include <stdio.h>
#include <inttypes.h>
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "servo_policy.h"
static esp_err_t pulse_set(uint16_t pulse){
 /* One owner, no fade/other task uses this channel. The thread-safe combined
    API needs an installed fade service in IDF5.5.5; it is deliberately not used. */
 esp_err_t e=ledc_set_duty(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0,servo_duty(pulse));
 return e==ESP_OK?ledc_update_duty(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0):e;
}
void app_main(void){
 gpio_config_t in={.pin_bit_mask=1ULL<<GPIO_NUM_5,.mode=GPIO_MODE_INPUT};ESP_ERROR_CHECK(gpio_config(&in));
 ledc_timer_config_t timer={.speed_mode=LEDC_LOW_SPEED_MODE,.duty_resolution=LEDC_TIMER_14_BIT,.timer_num=LEDC_TIMER_0,.freq_hz=50,.clk_cfg=LEDC_USE_APB_CLK};ESP_ERROR_CHECK(ledc_timer_config(&timer));
 ledc_channel_config_t channel={.gpio_num=GPIO_NUM_6,.speed_mode=LEDC_LOW_SPEED_MODE,.channel=LEDC_CHANNEL_0,.timer_sel=LEDC_TIMER_0,.duty=0,.hpoint=0};ESP_ERROR_CHECK(ledc_channel_config(&channel));ESP_ERROR_CHECK(ledc_stop(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0,0));
 printf("V06 REQUEST50Hz/14bit; SDK frequency=%"PRIu32"Hz; no physical waveform/position feedback. Release first, then hold ARM1s. External servo5V only; no automatic startup position.\n",ledc_get_freq(LEDC_LOW_SPEED_MODE,LEDC_TIMER_0));
 Servo state={0};bool was=false,fault=false;uint16_t last=0;unsigned reason=0;
 for(;;){
  servo_tick(&state,gpio_get_level(GPIO_NUM_5)==0,(uint64_t)esp_timer_get_time());
  if(!fault&&(was!=state.active||(state.active&&last!=state.pulse))){
   esp_err_t e=state.active?pulse_set(state.pulse):ledc_stop(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0,0);
   if(e!=ESP_OK){fault=true;(void)ledc_stop(LEDC_LOW_SPEED_MODE,LEDC_CHANNEL_0,0);printf("PWM_API_FAULT=%s; stop requested; reset only after diagnosis\n",esp_err_to_name(e));}
   else printf("SERVO_REQUEST active=%u pulse_us=%u duty=%"PRIu32"; signal/position unmeasured\n",state.active,state.pulse,state.active?servo_duty(state.pulse):0);
  }
  if(reason!=state.reason){reason=state.reason;printf("STOP_REASON=%u; PWM stop is not power removal or observed shaft stop\n",reason);}
  was=state.active;last=state.pulse;vTaskDelay(pdMS_TO_TICKS(20));
 }
}

// ---- main/servo_policy.h ----
/* SPDX-License-Identifier: MIT */
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct {
 bool initialized,candidate,stable,released,holding,active;
 uint64_t changed,pressed,started,stepped,last;
 uint16_t pulse;int direction;unsigned reason;
} Servo;
/* reason:0 waiting/normal,1 released,2 ten-second limit,3 owner-clock gap.
   Time budgets are checked only when this owner runs, never a hardware stop guarantee. */
static inline void servo_tick(Servo *s,bool pressed,uint64_t now){
 if(!s->initialized){*s=(Servo){.initialized=true,.candidate=pressed,.stable=true,.changed=now,.last=now,.pulse=1500,.direction=1};}
 bool gap=now<s->last||now-s->last>250000;s->last=now;
 if(gap){s->active=false;s->released=false;s->holding=false;s->candidate=pressed;s->stable=true;s->changed=now;s->reason=3;}
 if(pressed!=s->candidate){s->candidate=pressed;s->changed=now;}
 if(now>=s->changed&&now-s->changed>=50000&&s->stable!=s->candidate){
  s->stable=s->candidate;
  if(!s->stable){s->released=true;s->holding=false;}
  else if(s->released){s->pressed=now;s->holding=true;}
 }
 if(!pressed){if(s->active)s->reason=1;s->active=false;}
 if(s->active&&now-s->started>=10000000){s->active=false;s->released=false;s->holding=false;s->reason=2;}
 if(!s->active&&pressed&&s->stable&&s->holding&&s->released&&now-s->pressed>=1000000){
  s->active=true;s->released=false;s->holding=false;s->started=now;s->stepped=now;s->pulse=1500;s->direction=1;s->reason=0;
 }
 if(s->active&&now-s->started>=1000000&&now-s->stepped>=100000){
  s->stepped=now;s->pulse=(uint16_t)(s->pulse+5*s->direction);
  if(s->pulse>=1600){s->pulse=1600;s->direction=-1;}else if(s->pulse<=1400){s->pulse=1400;s->direction=1;}
 }
}
static inline uint32_t servo_duty(uint16_t pulse){return pulse<1400||pulse>1600?0:(uint32_t)(((uint64_t)pulse*16384+10000)/20000);}

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[3] GPIO模式、电平与外部上拉/下拉接口[4] 64位微秒单调时钟

10 / 机电控制与分层验收

默认构建的目标、时钟和资源范围

8MiB Flash、PSRAM关闭、PM关闭与UART0为本例实际配置。改defaults后重用旧sdkconfig不一定生效,须核最终生成值;OPI模组的存在不等于程序已经使用PSRAM。

代码 / 配置
# ---- sdkconfig.defaults ----
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
# CONFIG_SPIRAM is not set
# CONFIG_PM_ENABLE is not set
CONFIG_ESP_CONSOLE_UART_DEFAULT=y
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
CONFIG_FREERTOS_HZ=1000

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[5] 官方DevKitC1 v1.1固定GPIO与互斥供电选项

11 / 机电控制与分层验收

原样策略的合成检查全文

本文件运行在主机,输入的是合成按键与时间;assert通过不证明电机、舵机、LEDC波形或电源已经实际验证。编译命令在上面的“纯逻辑与真实物理分开”一节。

代码 / 配置
// ---- host_check.c ----
/* SPDX-License-Identifier: MIT */
#include <assert.h>
#include <stdio.h>
#include "main/servo_policy.h"
static uint64_t time_us;
static void steps(Servo *s,bool p,unsigned count){for(unsigned i=0;i<count;i++){servo_tick(s,p,time_us);time_us+=20000;}}
int main(void){
 Servo s={0};steps(&s,true,100);assert(!s.active);puts("PASS startup held never starts");
 steps(&s,false,5);steps(&s,true,50);assert(!s.active);steps(&s,true,5);assert(s.active&&s.pulse==1500);puts("PASS stable release then1s hold arms neutral");
 uint64_t start=s.started;while(time_us-start<1000000)steps(&s,true,1);assert(s.pulse==1500);steps(&s,true,1);assert(s.pulse==1505);puts("PASS neutral1s then5us scheduled increments");
 bool high=false,low=false;while(time_us-start<9990000){steps(&s,true,1);assert(s.pulse>=1400&&s.pulse<=1600);high|=s.pulse==1600;low|=s.pulse==1400;}assert(high&&low);steps(&s,true,2);assert(!s.active&&s.reason==2);steps(&s,true,100);assert(!s.active);puts("PASS bounded1400..1600 pulses and10s hold limit requires release");
 steps(&s,false,5);steps(&s,true,60);assert(s.active);steps(&s,false,1);assert(!s.active&&s.reason==1);puts("PASS raw release immediately requests signal stop at owner tick");
 steps(&s,false,5);steps(&s,true,60);assert(s.active);time_us+=250001;steps(&s,true,1);assert(!s.active&&s.reason==3);steps(&s,true,80);assert(!s.active);puts("PASS owner gap closes output and held input cannot rearm");
 assert(servo_duty(1399)==0&&servo_duty(1601)==0&&servo_duty(1400)==1147&&servo_duty(1500)==1229&&servo_duty(1600)==1311);puts("PASS explicit14bit pulse calculation and range rejection; not waveform measurement");
 time_us=UINT64_C(5)*UINT64_C(4294967296)*1000;s=(Servo){0};steps(&s,false,5);steps(&s,true,60);assert(s.active);puts("PASS full64bit microsecond time after five32bit millisecond cycles");
 puts("8 same-source synthetic groups passed; no servo, GPIO, waveform, angle or power measurement");
}

参考:[1] IDF5.5.5 LEDC API:计时、分辨率、duty与stop[2] 固定LEDC实现:stop/重新update与fade服务前置[4] 64位微秒单调时钟

BACK TO THE SOURCE

资料来源与版本说明

实际读固定LEDC/GPIO/计时实现与板针脚,厂商部件页及手册另留原文与摘要;编译、同源合成与真实机械/电气分开。FS90厂家/销售方电流差异与DRV8833 UVLO正文/表格差异均明确,不将规格当本站测量。资料核对日期:。资料核对、程序构建与实板测试分别记录,不互相替代。

  1. IDF5.5.5 LEDC API:计时、分辨率、duty与stop
  2. 固定LEDC实现:stop/重新update与fade服务前置
  3. GPIO模式、电平与外部上拉/下拉接口
  4. 64位微秒单调时钟
  5. 官方DevKitC1 v1.1固定GPIO与互斥供电选项
  6. Pololu2818 FS90:位置型、3.3V信号与脉宽范围
  7. 厂家链接FS90-C V1.0:电压、堵转栏、900..2100µs与死区
  8. Pololu伺服控制接口:脉宽而非占空比决定请求
  9. Pololu独立测试电流及非厂家定值注记