资讯动态

SmartKnob 力反馈旋钮:用软件定义止动与虚拟凹轮,10 分钟调出你要的阻尼手感

发布时间:2026/10/30 4:43:14 来源:尧图企业网站定制
SmartKnob 力反馈旋钮用软件定义止动与虚拟凹轮10 分钟调出你要的阻尼手感【免费下载链接】smartknobHaptic input knob with software-defined endstops and virtual detents项目地址: https://gitcode.com/gh_mirrors/smar/smartknob想要咔哒咔哒的段落手感却只能靠齿轮硬凑旋钮拧到边界那声闷响能不能变成一段越拧越软的阻尼墙SmartKnob 是款力反馈旋钮它把止动和凹轮咔哒感从机械结构里搬进代码用无刷云台电机配磁编码器做闭环扭矩控制让止动边界和虚拟凹轮全部由软件定义——手感从此是可调参数不是焊死的零件。花十分钟你能做到看懂虚拟凹轮是怎么靠角度差算出来的自己调position_width_radians、detent_strength_unit把阻尼拧到舒服用snap_point解决切换不干脆或位置乱跳对照排查嗡嗡声、空转卡顿、边界漂移这几类典型毛病它凭什么不同软件定义止动 vs 机械齿轮的三段差距传统旋钮的手感被齿轮结构锁死齿距是固定的想改多密一档就得换齿轮想改边界软硬几乎无解。SmartKnob 把这三件事都交给固件。时间线/倍速场景普通旋钮只能在固定齿距上停这里可以只让 1x、2x、4x 各有一个吸点中间完全顺滑非等距凹轮直接写进配置。边界手感从啪地撞死改成随角度渐弱的弹簧墙止动强度是个独立旋钮endstop_strength_unit和凹轮强度分开调。手感随场景变同一颗旋钮切个配置就能在精密微调和快速扫档之间切换不用动任何硬件。⚡系统全景电机控制任务与状态机是怎么分工的固件是几个 FreeRTOS 任务各司其职。核心在 motor_task.cpp它持有 SimpleFOCFOC 磁场定向控制库的BLDCMotor实例负责扭矩环和凹轮状态机。MotorTask读编码器 → 算凹轮位 → 出扭矩是力反馈的心脏。InterfaceTaskinterface_task.cpp走 USB 串口支持明文与 protobuf 两种协议负责下发配置、上送状态。DisplayTask驱动旋钮内那块圆形 LCD显示当前档位。Configurationconfiguration.cpp用 FFat 把电机/应变校准值存盘断电不丢。传感器默认推荐 MT6701SSI 带 CRC也兼容 TLV493D、MAQ430。每圈主循环大致这样走传感器刷新轴角落到motor.shaft_angle算当前轴角与最近凹轮中心的偏差偏差越过snap_point→ 整数位进/退一格凹轮中心平移一个position_width_radians把偏差喂进 PID 扭矩环边界处P换成止动强度FOC 把扭矩指令翻译成三相 PWM 去驱动电机每 5ms 把最新状态推给显示和主机侧。体验的来源虚拟凹轮与扭矩闭环的代码级拆解先搭好扭矩闭环后面所有手感才有落脚点。电机一初始化就切到扭矩控制模式PID 参数直接来自 mad2804.h 的宏motor.controller MotionControlType::torque; motor.voltage_limit FOC_VOLTAGE_LIMIT; motor.linkSensor(encoder); motor.PID_velocity.P FOC_PID_P; // 1 motor.PID_velocity.I FOC_PID_I; // 0 motor.PID_velocity.D FOC_PID_D; // 0.148 motor.PID_velocity.output_ramp FOC_PID_OUTPUT_RAMP; // 5000 motor.PID_velocity.limit FOC_PID_LIMIT; // 3这里借用 SimpleFOC 的速度环 PID 变量来跑扭矩好处是用 SimpleFOC Studio 就能串口实时改参。P 负责把偏差变回中心D 抑制高速时的过冲output_ramp限住扭矩跳变速度limit封顶最大输出。虚拟凹轮的吸附本质是维护一个凹轮中心并和它比距离偏差一旦越线就平移中心、整数位走一格// 轴当前角度 与 最近凹轮中心 的偏差 float angle_to_detent_center motor.shaft_angle - current_detent_center; float snap_point_radians config.position_width_radians * config.snap_point; if (angle_to_detent_center snap_point_radians current_position config.min_position) { current_detent_center config.position_width_radians; // 凹轮中心前移一格 current_position--; } else if (angle_to_detent_center -snap_point_radians current_position config.max_position) { current_detent_center - config.position_width_radians; current_position; }snap_point是越过多少比例才算切档它同时给了迟滞要越过半个档宽才换挡松手时又被拉回中心这就是咔哒的来源。真实代码在此基础上还叠加了snap_point_bias用来做非对称凹轮。真正让不同档宽都不吵的是 D 项随凹轮宽度自适应——细档给大 D、粗档给小 D分三段线性插值const float derivative_lower_strength config.detent_strength_unit * 0.08; const float derivative_upper_strength config.detent_strength_unit * 0.02; const float derivative_position_width_lower radians(3); const float derivative_position_width_upper radians(8); const float raw derivative_lower_strength (derivative_upper_strength - derivative_lower_strength) / (derivative_position_width_upper - derivative_position_width_lower) * (config.position_width_radians - derivative_position_width_lower); motor.PID_velocity.D config.detent_positions_count 0 ? 0 : CLAMP(raw, min(derivative_lower_strength, derivative_upper_strength), max(derivative_lower_strength, derivative_upper_strength));意思是3° 的细档拿到 0.08×强度 的 D8° 的粗档只拿 0.02×强度中间线性过渡。D 太大粗档会放大传感器噪声变成噪声D 太小细档又咔不出来这段逻辑就是在两头之间自动找平衡一旦启用了自定义凹轮位detent_positions就干脆把 D 归零避免多重咔哒打架。最后是个顺手的小技巧——触觉点击用一段推一下再拉回来的扭矩脉冲模拟按压case CommandType::HAPTIC: { float strength command.data.haptic.press ? 5 : 1.5; // 按下更强 motor.move(strength); for (uint8_t i 0; i 3; i) { motor.loopFOC(); delay(1); } motor.move(-strength); for (uint8_t i 0; i 3; i) { motor.loopFOC(); delay(1); } motor.move(0); break; }按下比松开强5 vs 1.5两三次loopFOC的短爆发就是一次哒。它独立于凹轮逻辑适合在触发某个事件时给主机侧一个明确的触觉确认。调优路线position_width_radians 与 detent_strength_unit 起步取值表手感的旋钮字段都来自 smartknob.proto 里的SmartKnobConfig下面是建议的起手值字段它管什么建议起手值position_width_radians相邻凹轮间的角度宽度弧度精细 3°–5°快切 10°–15°detent_strength_unit凹轮吸力强度0 表示关0.5–1.0超过 1 易不稳endstop_strength_unit边界止动扭矩0 关0.5–1.0约凹轮的 1.5–2×snap_point越线才换挡的滞后阈值0.5–1.1固件强制 ≥0.5snap_point_bias非对称凹轮偏置松手易回中默认 0detent_positions最多 5 个磁性凹轮位想要非等距吸点时填调优路径由稳到细先校准电机跑一次自动校准拿到方向、极对数、电角度零位写进持久化配置不校准后面全白搭。定档宽设position_width_radians先按一格里想放多少有效位来估。给吸力上detent_strength_unit边转边加直到松手能稳稳停在档上。磨切换用snap_point找既干脆又不乱跳的点偏大更稳、偏小更灵敏。场景化收尾给不同应用存不同配置需要回中感就加snap_point_bias。想玩更野的detent_positions让你只给指定档位加吸点做出对数刻度、音量重点位这类非线性手感配合snap_point_bias还能做按住松手会滑回原点的回归键。排错手册嗡嗡声、空转卡顿与边界漂移对照排查1. 现象凹轮强度调很低时空转也有咔哒卡顿原因电机 cogging齿槽效应不通电也想停在某些角度太大盖过了软件凹轮。 解决换低 cogging 的 32mm 空心轴无刷云台电机cogging 严重时低强度/细档会直接被机械咬合干扰。2. 现象旋转时发出嗡嗡/蜂鸣声原因D 项放大了磁编码器的噪声或滤波不够。 解决调大FOC_LPFmad2804.h 中默认 0.0075平滑输出必要时降低 D优先用带 CRC 的 MT6701SSI降低数据毛刺。3. 现象位置在边界或某档附近来回乱跳原因snap_point太小迟滞不足抖动就能触发换挡。 解决固件已强制snap_point ≥ 0.5把它往上调0.7–1.1加迟滞确认detent_strength_unit没有超过 1。4. 现象松手后旋钮不回凹轮中心、慢慢漂走原因未校准或校准数据不准凹轮中心跟真实位置对不上。 解决重跑电机校准注意主循环在高速60 rad/s时会主动撤掉扭矩防止失控所以越转越飘往往不是控制环的锅而是零位/方向没对准。延伸与获取固件入口、协议文件与示例代码位置任务与启动顺序看 firmware/src/main.cppDisplay、Motor、Interface 三个任务在这里串起来。力反馈核心逻辑在 firmware/src/motor_task.cppFOC 参数在 firmware/src/motors/。主机↔旋钮协议字段min/max_position、detent_positions等定义在 proto/smartknob.proto。想动手连一台Python 示例 software/python/simple_example.py 直接改配置发下去Web/Node 侧在 software/js/packages/ 里有 core、webserial、示例 CLI。拉完整工程git clone https://gitcode.com/gh_mirrors/smar/smartknob。把手感当成一组可下发、可回读、可随场景切换的参数旋钮就不再是被动元件而是一块可以重写的输入介质。 下一站或许就是把这套力反馈接到你的时间线、播放器或合成器里——让它替你的手指记住哪里该停。【免费下载链接】smartknobHaptic input knob with software-defined endstops and virtual detents项目地址: https://gitcode.com/gh_mirrors/smar/smartknob创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑