SimpleFOC源码学习08(v2.3.2) - 霍尔编码器HallSensor.cpp与HallSensor.h,背后的状态机—6个扇区是怎么驱动 FOC 的?

news2026/4/15 23:04:28
导言github 源码https://github.com/simplefoc/Arduino-FOC/blob/v2.3.2/src/sensors/HallSensor.hhttps://github.com/simplefoc/Arduino-FOC/blob/v2.3.2/src/sensors/HallSensor.cpp在第 8 篇分析了增量式编码器Encoder之后这篇来看另一类在 BLDC 电机上极为常见的位置传感器——霍尔传感器。为什么 BLDC 电机要用霍尔传感器在学Encoder时你看到的是一种外挂式的测量方案用户额外购买一个独立的光电编码器再把它安装到电机轴末端。但很多 BLDC 电机比如平衡车、航模、云台、hoverboard 电机本身就在定子里集成了 3 个霍尔传感器几乎不需要额外成本。它们最初并不是为 FOC 准备的而是为更早期的六步换向trapezoidal commutation提供转子位置反馈。这也决定了HallSensor的几个核心特点分辨率很低一个电周期只有 6 个离散位置每档对应 60° 电角度它天然测的是电角度不是机械角度因此必须结合极对数pp才能换算不需要外部 ADC/SPI3 根数字输入引脚就够了不适合高精度位置控制但通常足够做速度闭环如果需要提升分辨率也可以在此基础上加插补算法后续的《源码改进》系列会专门讨论一、硬件原理——3 个霍尔的 6 个状态定子里的 3 个霍尔传感器 A、B、C在电角度上彼此错开 120°。当带永磁体的转子旋转一个电周期时每个霍尔都会输出一个方波三路信号之间的相位差正好也是 120°。如果把 ABC 这 3 个二进制位拼成一个 3-bit 数理论上有 8 种组合000~111。但在理想工作状态下真正会稳定出现的只有 6 种。000和111通常被视为非法状态它们往往意味着接线异常、信号噪声或者边沿过渡时的瞬态异常。这 6 种合法状态按顺序循环正好把一个电周期切成 6 份每份 60° 电角度称为一个sector扇区。1.1、霍尔码的本质3 个独立方波拼出来的二进制数ABC 三个霍尔传感器各自输出一个方波彼此错开 120° 电角度。把它们拼成 3-bit 数时每一位的权重是固定的hall_state A×4 B×2 C×1。但问题在于每次只有一个 bit 翻转这和 Gray code 的性质相似而翻转的是哪一位取决于当前物理位置和二进制权重大小没有直接关系。从下面这个实际序列可以看到在这里采用的相序约定下顺时针旋转时的翻转顺序是C、A、B、C、A、B…这是由传感器的物理排布和接线顺序共同决定的步骤翻转的 bitA B C十进制值变化量起始1 0 041C 翻转 (权重1)1 0 1512A 翻转 (权重4)0 0 11-43B 翻转 (权重2)0 1 1324C 翻转 (权重1)0 1 02-15A 翻转 (权重4)1 1 0646B 翻转 (权重2)1 0 04-2差值序列是1, -4, 2, -1, 4, -2。可以看到如果直接看hall_state的数值增减序列并不连续。你可以试着自己把这列差值排出来看看——规律一出来就会明白为什么 SimpleFOC 选择了查表而不是直接比较数值大小。1.2、ELECTRIC_SECTORS[]到底是一张什么样的表下面这张图把 8 个索引位置全部展开帮你看清它的结构// seq 1 5 4 6 2 3 1 000 001 010 011 100 101 110 111constint8_tELECTRIC_SECTORS[8]{-1,0,4,5,2,1,3,-1};1.3、通过ELECTRIC_SECTORS[]将hall_state变成扇区 n源码注释写的是seq 1 5 4 6 2 3 1。这里表达的是按库中约定的顺时针方向hall_state会沿着这条序列循环。完整映射如下第 1~5 步中new - old始终是1因此可以直接判定为 CW。第 6 步里sector 从 5 回绕到 0差值变成0 - 5 -5。此时触发 -3条件程序将其识别为overflow也就是跨零回绕而不是一次真正的 CCW 跳变同时执行electric_rotations directionDirection::CW 1表示又走完了一个电周期。它本质上是一张手工构造的查找表用来把看起来不连续的hall_state重新映射成连续的 0~5 扇区编号。这样一来updateState()里的方向判断就会非常简单if(new_electric_sector-electric_sector1)→ CWif(new_electric_sector-electric_sector-1)→ CCW// 溢出/下溢用 3 / -3 处理跨零二、cpr的全新含义看构造函数HallSensor::HallSensor(int_hallA,int_hallB,int_hallC,int_pp){...cpr_pp*6;// hall has 6 segments per electrical revolution }这行非常值得停下来琢磨。在Encoder里cpr通常可以直接理解为机械一圈内的计数数目。但在HallSensor里它的含义稍微绕一点一个电周期有 6 个 sector一个机械周期包含pp个电周期pp pole pairs极对数所以机械一圈内的 sector 总数6 × pp这就是这里的cpr举个具体例子一个 hoverboard 电机如果pp 15那么cpr 90。也就是说电机机械转一圈时你最多只能得到 90 个离散位置点每个点之间相差360° / 90 4°机械角度。和光电编码器动辄 1000~10000 的 PPR 相比这个分辨率至少低了一个数量级。这也解释了为什么HallSensor更适合做速度反馈而不是高精度位置反馈。三、中断回调霍尔状态更新// A channelvoidHallSensor::handleA(){A_activedigitalRead(pinA);updateState();}// B channelvoidHallSensor::handleB(){B_activedigitalRead(pinB);updateState();}// C channelvoidHallSensor::handleC(){C_activedigitalRead(pinC);updateState();}每个函数都只有两行代码非常简洁。核心区别在于状态信息到底是局部可判定的还是必须全局合并后才能判定。在Encoder里每次 A 相或 B 相跳变时方向信息已经局部可得例如可以通过比较另一相当前电平来判断方向所以两个回调可以各自独立处理计数。在HallSensor里单独看某一根线的跳变还不够。你必须把(A, B, C)三位状态合起来才能判断当前转子处于哪个 sector。因此这三个回调函数的职责都一样先更新自己对应的那一位电平再统一调用updateState()做整体处理。四、updateState() - 本文件的心脏/** * Updates the state and sector following an interrupt */voidHallSensor::updateState(){longnew_pulse_timestamp_micros();int8_tnew_hall_stateC_active(B_active1)(A_active2);// glitch avoidance #1 - sometimes we get an interrupt but pins havent changedif(new_hall_statehall_state){return;}hall_statenew_hall_state;int8_tnew_electric_sectorELECTRIC_SECTORS[hall_state];if(new_electric_sector-electric_sector3){//underflowdirectionDirection::CCW;electric_rotationsdirection;}elseif(new_electric_sector-electric_sector(-3)){//overflowdirectionDirection::CW;electric_rotationsdirection;}else{direction(new_electric_sectorelectric_sector)?Direction::CW:Direction::CCW;}electric_sectornew_electric_sector;// glitch avoidance #2 changes in direction can cause velocity spikes. Possible improvements needed in this areaif(directionold_direction){// not oscilating or just changed directionpulse_diffnew_pulse_timestamp-pulse_timestamp;}else{pulse_diff0;}pulse_timestampnew_pulse_timestamp;total_interrupts;old_directiondirection;if(onSectorChange!nullptr)onSectorChange(electric_sector);}4.1、拼接 3-bit 状态int8_tnew_hall_stateC_active(B_active1)(A_active2);把三个独立的 0/1 位拼成一个 3-bit 整数A 在最高位C 在最低位。于是new_hall_state ∈ {0..7}正好对应ELECTRIC_SECTORS[]的索引。4.2、毛刺防御#1if(new_hall_statehall_state){return;}这和你在Encoder里看到的if (A ! A_active)本质类似硬件中断系统偶尔会出现虚假触发比如电磁干扰、边沿不干净或者输入信号抖动。软件层面最直接的防御就是先判断状态到底有没有变化如果没变就立刻返回。这种幂等性检查是嵌入式代码里的常见写法。4.3、查表获取新 sectorint8_tnew_electric_sectorELECTRIC_SECTORS[hall_state];这是一次O(1)的查表没有额外算术。不过这里暗含一个小隐患如果因为噪声、接线问题或者采样到了瞬时非法状态000/111那么new_electric_sector就会变成-1后面的方向判断也会被带偏。SimpleFOC 这里没有显式处理这种情况因此这是实战中值得补防御的一个点。如果你在移植时发现方向判断偶尔出错可以考虑在查表之后加一行守卫int8_tnew_electric_sectorELECTRIC_SECTORS[hall_state];// 建议补充过滤非法状态000 或 111 对应 sector -1if(new_electric_sector0){return;// 忽略噪声导致的非法状态不更新 direction/sector}对应这张表4.4、方向判断 圈数累积if(new_electric_sector-electric_sector3){directionDirection::CCW;// underflow: e.g. 0 → 5electric_rotationsdirection;}elseif(new_electric_sector-electric_sector(-3)){directionDirection::CW;// overflow: e.g. 5 → 0electric_rotationsdirection;}else{direction(new_electric_sectorelectric_sector)?Direction::CW:Direction::CCW;}这段逻辑值得重点理解。sector 的合法变化一次只能跨 1 格所以在正常情况下new - old只可能是1或-1。但在边界处也就是从 sector 5 回到 sector 0或者从 sector 0 退回 sector 5 时差值会突然变成-5或5。这时就不能再按数值大小粗暴判断而必须把它识别为一次wraparound环绕回跳。这里有一个细节值得单独说清楚electric_rotations direction并不是把枚举值赋给整数的魔法。SimpleFOC 中Direction是普通枚举非enum class其定义如下enumDirection:int8_t{CW1,CCW-1,UNKNOWN0};所以electric_rotations direction等价于CW 时 1CCW 时 -1。理解electric_rotations的含义非常关键electric_rotations 电周期的累计圈数不是机械圈数electric_sector 当前电周期内的 sector 编号(0~5)总位置 electric_rotations × 6 electric_sector单位是第几个 sector所以electric_rotations只会在5↔0 的 wraparound处变化这正是检测|diff| 3的意义。为什么阈值取 3因为正常跳变是±1跨零回绕是±53 正好把这两种情况分开。也就是说在理想情况下合理的 diff 只会是±1或±5如果出现±2、±3、±4那通常意味着丢中断、噪声或者状态采样异常。4.5、毛刺防御 #2方向翻转时清空速度if(directionold_direction){pulse_diffnew_pulse_timestamp-pulse_timestamp;}else{pulse_diff0;}这是一个很实用的工程防御。想象一下如果电机刚才还在 CW 转随后因为抖动或者真的开始减速并反向那么第一个 CCW 的pulse_diff会是什么它实际上会包含上一次 CW 脉冲到这一次 CCW 脉冲的整段时间。但这段时间对应的物理过程往往是减速、停下、再反向加速显然不是一个稳定方向下的速度测量值。如果直接拿它算速度曲线上就很容易出现明显尖峰。所以代码的处理策略是只要检测到方向刚发生变化就先把pulse_diff清零。这样下一次getVelocity()会返回 0等到再下一次脉冲到来、方向稳定下来之后再恢复正常测速。这就是注释里那句 “changes in direction can cause velocity spikes” 的含义作者知道这是一个实际存在的问题而这里给出的是一种比较保守的缓解方法。4.6、total_interrupts和onSectorChange回调total_interrupts;if(onSectorChange!nullptr)onSectorChange(electric_sector);total_interrupts是一个调试计数器。注释里提到它有时可以用来识别中断异常比如弱上拉导致一秒钟触发大量中断。实战中如果你发现这个数字异常暴涨通常说明信号质量有问题。onSectorChange是一个用户可选的回调钩子。sector 变化时用户可以立即收到通知并据此实现最基础的六步换向而不一定非要走 FOC 这条路径。这是 SimpleFOC 留出的一个扩展接口。五、getSensorAngle()—— 从 sector 到弧度floatHallSensor::getSensorAngle(){return((float)(electric_rotations*6electric_sector)/(float)cpr)*_2PI;}这一行把当前累计经过了多少个 sector映射成累计机械角位置弧度。拆开看electric_rotations * 6 electric_sector→ 从上电到现在累计经过的 sector 总数/ cpr→ 归一化到转过了多少个机械圈* _2PI→ 换成弧度记住cpr pp × 6。举个例子如果pp 7那么cpr 42。假设当前electric_rotations 3、electric_sector 4那么总 sector 数就是22对应的机械角位置为22 / 42 × 2π ≈ 3.29 rad ≈ 188°。注释里那句TODO: numerical precision issue here if the electrical rotation overflows the angle will be lost提醒的是一个长期运行时的精度问题。这和 Sensor 基类里提到的float很难同时兼顾很大的圈数和很细的小角度其实是同一个问题。六、update()—— 填充 Sensor 基类字段voidHallSensor::update(){noInterrupts();angle_prev_tspulse_timestamp;longlast_electric_rotationselectric_rotations;int8_tlast_electric_sectorelectric_sector;interrupts();angle_prev((float)((last_electric_rotations*6last_electric_sector)%cpr)/(float)cpr)*_2PI;full_rotations(int32_t)((last_electric_rotations*6last_electric_sector)/cpr);}结构和Encoder::update()几乎一模一样三件套完全一致noInterrupts()/interrupts()临界区内拷贝 volatile 数据把累积值拆成圈数部分(/) 和圈内角度部分(%)填充 Sensor 基类的full_rotations、angle_prev、angle_prev_ts这正是 Sensor 基类设计的价值所在无论底层是光电编码器还是霍尔传感器update()最后填充的都是同一组字段。因此基类里的getAngle()、getPreciseAngle()等接口就可以对所有子类使用统一逻辑。七、getVelocity()—— 测周期法T 法这里和Encoder不一样。Encoder用的是混合 M/T 法而HallSensor用的是更纯粹的 T 法floatHallSensor::getVelocity(){noInterrupts();longlast_pulse_timestamppulse_timestamp;longlast_pulse_diffpulse_diff;interrupts();if(last_pulse_diff0||((long)(_micros()-last_pulse_timestamp)last_pulse_diff*2)){return0;}else{returndirection*(_2PI/(float)cpr)/(last_pulse_diff/1000000.0f);}}为什么要用 T 法因为 Hall 的分辨率太低M 法固定时间窗内数脉冲在低速时经常会遇到一个脉冲都数不到的情况。T 法则直接测相邻两次 sector 切换之间的时间差再反推速度。由于每次 sector 切换都对应一个固定角度增量2π / cpr所以这种做法在低分辨率传感器上更实用。这里有两个关键防御①last_pulse_diff 0这说明方向刚刚翻转过回忆 4.5 节当前测量不可信所以直接返回 0。②_micros() - last_pulse_timestamp last_pulse_diff * 2这是一个很典型的速度过期检测。它实际上在问“从上一次脉冲到现在已经过去的时间是否超过了上一个脉冲周期的 2 倍”把这句话翻译成物理意义就是如果电机在平稳减速那么脉冲间隔应该逐渐变长但如果距离上次脉冲的时间已经变成上次脉冲间隔的 2 倍以上说明当前转速已经明显低于之前那次测量值。这时如果还沿用旧的pulse_diff来算速度就会明显高估所以程序干脆直接返回 0。这可以看作是Encoder::getVelocity()里if (Th 0.1f) pulse_per_second 0的 Hall 版本只不过这里使用的是相对过期而不是绝对超时因此更自适应。最后的速度公式direction*(_2PI/cpr)/(last_pulse_diff/1e6)_2PI / cpr 每个 sector 对应的机械角度增量弧度last_pulse_diff / 1e6 两个 sector 之间的时间差秒两者相除 角速度rad/s乘direction得到带符号速度八、init()—— 一个容易被忽略的小细节A_activedigitalRead(pinA);B_activedigitalRead(pinB);C_activedigitalRead(pinC);updateState();init()结尾这四行很重要它会主动读取一次当前三个引脚的电平并立即调用一次updateState()。这样一来在用户调用enableInterrupts()之前electric_sector和hall_state就已经有了合理初值。如果不做这一步第一次中断到来时electric_sector可能还停留在默认值从而导致一次虚假的大跳变判断。九、整体架构对比Encoder vs HallSensor结合上图可以把Encoder和HallSensor的差异归纳为三个层面中断触发模式不同。Encoder的两个回调handleA/handleB各自能独立判断方向——拿到 A 相跳变时读一下 B 相当前电平就够了局部信息即可决策。HallSensor则不行任何一路跳变都只给了信息的三分之一必须把三位状态合并才能确定扇区所以三个回调全部汇聚到同一个updateState()来统一处理。位置精度与速度估算的取舍不同。Encoder每个机械圈可以产生数千到数万个脉冲M/T 混合法可以在较宽的速度范围内保持良好的精度。HallSensor每机械圈最多6 × pp个离散点低速时脉冲极度稀疏因此只能依赖纯 T 法并配合方向翻转清零和速度过期检测这两道软件防线来维持基本可用的速度反馈。和 Sensor 基类的对接方式相同但数据来源不同。两者的update()最终都填充同一组字段full_rotations、angle_prev、angle_prev_ts让上层控制器可以无差别地调用。区别在于数据的来源Encoder靠增量脉冲计数HallSensor靠electric_rotations × 6 electric_sector的累积扇区数。十、这一篇可以记住的几个结论ELECTRIC_SECTORS[]是一张手工构造的查找表把看起来不连续的hall_state重新映射为连续的 0~5 扇区编号是整个方向判断逻辑能够简洁运作的基础。方向判断阈值 3 的选取不是随意的正常跳变是±1跨零回绕是±53 正好居中分割两种情况。cpr pp × 6中的cpr含义是机械一圈内的扇区总数而不是脉冲数极对数越大cpr越高分辨率也越高。pulse_diff 0是方向翻转时的速度清零保护而过去时间超过上次脉冲周期 2 倍是停转时的速度归零保护——两道防线的触发时机不同。init()里主动读一次引脚电平再调updateState()是为了在首次中断到来前就建立合理的初始状态避免第一次跳变被误判为大幅度位置变化。三个中断回调都汇聚到updateState()的设计是由霍尔传感器状态必须全局合并才可判定的物理特性决定的而不是代码风格选择。你在用霍尔传感器做速度闭环时有没有遇到过低速段速度反馈抖动、或者方向判断偶尔出错的问题这类问题往往比调 PID 参数更难排查——接线顺序、上拉阻值、中断优先级都可能是根因。欢迎在评论区聊聊你的排查思路说不定就帮到了下一个踩坑的人。下一篇进入磁传感器系列看基于 SPI/I2C 接口的MagneticSensorSPI是如何在绝对角度读取和速度估算之间做权衡的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2521385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…