新闻详情

新闻详情

首页 / 资讯中心 / 详情

从零手搓AI工程:深入理解张量、自动求导与推理服务

发布时间:2026/9/29 1:13:42来源:尧图网络
从零手搓AI工程:深入理解张量、自动求导与推理服务
1. 从零手搓AI工程为什么我不建议你直接调包很多人一听到“AI工程”这四个字第一反应就是打开某个云平台拖几个组件调几个API然后跑通一个Demo就觉得自己已经入门了。我刚开始接触这个方向的时候也是这么想的直到有一次线上推理服务在高峰期直接雪崩日志里全是显存溢出和请求超时我才意识到——只会调包的人根本不知道模型在底层到底经历了什么。ai-engineering-from-scratch这个项目标题核心不在“AI”而在“from scratch”。它代表的是一种学习路径不依赖高层框架的黑盒封装从最基础的张量运算、自动求导、损失函数、优化器开始一步步把整个训练和推理链路亲手搭出来。这条路走起来慢但走完之后你对AI系统的理解会发生质变。这篇文章适合三类人第一类是有一定编程基础、想真正搞懂AI系统内部运转机制的开发者第二类是在工作中已经用过一些AI工具但遇到性能瓶颈或诡异Bug时无从下手的工程师第三类是想从传统软件工程转型到AI工程方向但不想只停留在“调参侠”层面的朋友。我会把整个从零构建AI工程体系的关键环节拆开来讲包括环境搭建、核心模块实现、训练流程设计、推理服务部署以及我在实际操作中踩过的那些坑。需要提前说明的是这篇文章不会教你如何训练一个超越GPT的大模型那是工程团队和算力集群的事。我要讲的是如何用一台普通开发机从零把AI工程的核心骨架搭起来让你具备独立排查问题、优化性能、设计架构的能力。这个能力比会调多少个API重要得多。2. 环境搭建别急着装框架先把地基打牢2.1 为什么我坚持用原生Python起步很多教程一上来就让你装这个框架那个库结果环境冲突、版本不兼容的问题一大堆。我的做法是先用最干净的Python环境只装必要的数值计算库把核心逻辑用原生代码写一遍。这样做的好处是你能清楚地知道每一步在算什么而不是被框架的抽象层遮住眼睛。具体来说我建议用Python 3.10以上的版本创建一个独立的虚拟环境。虚拟环境这件事看起来是老生常谈但我见过太多人因为全局环境里装了几十个包最后连自己项目依赖哪个版本都搞不清楚。用venv或者conda都行关键是隔离。python -m venv ai-scratch source ai-scratch/bin/activate # Linux/Mac # 或者 ai-scratch\Scripts\activate # Windows装包的时候初期只需要NumPy就够了。NumPy提供了多维数组和基础线性代数运算这是所有AI计算的基石。你可能会问为什么不直接上PyTorch或者TensorFlow因为这两个框架虽然强大但它们的自动求导和GPU调度是封装好的你如果连矩阵乘法怎么手动实现都不清楚后面遇到梯度爆炸或者维度不匹配的问题根本无从排查。提示在安装NumPy之前确认你的pip已经升级到最新版本否则在某些系统上会遇到编译错误。用pip install --upgrade pip先更新一下。2.2 硬件选型的现实考量说到硬件很多人纠结要不要买显卡。我的建议是学习阶段CPU完全够用。你手搓的那些小规模矩阵运算和梯度计算CPU跑起来毫无压力。等你真正需要训练大模型的时候再考虑租用云算力或者购买显卡也不迟。但有一个硬件指标你需要关注内存。AI工程中经常需要处理大批量数据内存不足会导致频繁的磁盘交换速度直接掉一个数量级。我建议至少16GB内存起步如果预算允许32GB会更从容。另外SSD是必须的机械硬盘在读取大规模数据集时会成为严重瓶颈。如果你确实想用GPU加速那就要提前规划好CUDA环境的配置。这里有个坑CUDA版本、显卡驱动版本、深度学习框架版本三者之间必须严格匹配。我见过太多人因为版本不匹配折腾一整天都跑不起来一个简单的矩阵乘法。我的经验是先确定你要用的框架版本然后去查它官方文档推荐的CUDA版本最后再装对应的显卡驱动。顺序不能反。2.3 目录结构的设计逻辑一个清晰的目录结构能让你在项目变大之后依然保持掌控感。我习惯把项目分成这几个部分ai-scratch/ ├── core/ # 核心计算模块 │ ├── tensor.py # 张量基础操作 │ ├── autograd.py # 自动求导 │ └── nn.py # 神经网络层 ├── data/ # 数据处理 │ ├── loader.py # 数据加载 │ └── preprocess.py # 预处理 ├── train/ # 训练相关 │ ├── loop.py # 训练循环 │ └── optimizer.py # 优化器 ├── inference/ # 推理服务 │ └── server.py # 服务入口 └── tests/ # 测试用例这个结构的好处是职责分明。core目录里的代码不依赖任何外部数据可以单独测试data目录负责把原始数据转换成模型能吃的格式train目录只管训练逻辑inference目录处理线上服务。每个模块之间的耦合度低改一处不会牵连全局。3. 核心模块手搓实录张量、自动求导与网络层3.1 张量AI计算的原子单元张量说白了就是多维数组但它在AI工程里有特殊的含义它需要支持自动求导。我手搓的第一个版本只实现了基础的加减乘除和矩阵乘法结果发现根本不够用。后来逐步加上了广播机制、维度变换、索引操作才勉强能支撑一个简单的神经网络。实现张量的关键点在于每个张量需要记录三个东西——数据本身、梯度值、以及它是怎么被计算出来的也就是计算图。计算图这个东西你可以把它想象成一张族谱每个张量都知道自己的“父母”是谁这样在反向传播的时候才能沿着族谱一路把梯度传回去。class Tensor: def __init__(self, data, requires_gradFalse): self.data np.array(data, dtypenp.float32) self.grad None self.requires_grad requires_grad self._backward lambda: None self._prev set()上面这段代码是我简化后的核心结构。_backward是一个函数定义了如何把梯度传给前一个节点_prev记录了所有前驱节点。每次做运算的时候都要动态地构建这些关系。这里有个容易忽略的细节数据类型。我一开始用默认的float64结果内存占用直接翻倍训练速度也慢了不少。后来统一改成float32才回到正常水平。AI计算对精度的要求没有科学计算那么苛刻float32在绝大多数场景下都够用。3.2 自动求导反向传播的引擎自动求导是AI框架最核心的能力之一。没有它你就得手动推导每一个参数的梯度公式那基本上是不可完成的任务。我实现自动求导的思路是每个运算操作都定义一个前向计算函数和一个反向梯度函数反向函数负责把输出端的梯度乘以本地梯度然后累加到输入端。以加法为例前向是c a b反向就是a.grad c.grad和b.grad c.grad。因为加法对两个输入的偏导数都是1所以梯度直接传递。乘法稍微复杂一点c a * b的反向是a.grad c.grad * b.data和b.grad c.grad * a.data。矩阵乘法就更绕了。假设C A B那么A.grad C.grad B.TB.grad A.T C.grad。这个推导过程我建议你亲手在纸上推一遍推完之后你对矩阵维度的敏感度会大幅提升。注意在实现反向传播时一定要用而不是来累加梯度。因为一个张量可能被多个下游节点使用它的梯度是所有这些路径传回来的梯度之和。我当初就是因为用了导致梯度被覆盖模型怎么都训不起来排查了大半天才发现问题。3.3 网络层从线性层到激活函数有了张量和自动求导搭建网络层就是水到渠成的事。最基础的线性层本质上就是一个矩阵乘法加上偏置项y x W b。这里的W和b是需要学习的参数初始化的时候不能全设为零否则所有神经元的输出都一样反向传播时梯度也相同网络永远学不到东西。我常用的初始化方法是He初始化或者Xavier初始化。简单来说He初始化适合ReLU激活函数Xavier适合Sigmoid或Tanh。初始化的标准差跟输入维度和输出维度有关具体公式这里不展开你只需要记住初始化做得好训练收敛快初始化做得差模型直接摆烂。激活函数方面ReLU是最常用的选择计算简单梯度也好求。但它有个问题负半轴的梯度为零如果某个神经元的输入长期为负这个神经元就“死”了再也无法更新。为了解决这个问题后来出现了LeakyReLU、ELU等变体。我在实际项目中如果发现模型训练过程中损失下降异常缓慢第一件事就是检查有多少神经元处于“死亡”状态。class Linear: def __init__(self, in_features, out_features): # He初始化 std np.sqrt(2.0 / in_features) self.W Tensor(np.random.randn(in_features, out_features) * std, requires_gradTrue) self.b Tensor(np.zeros(out_features), requires_gradTrue) def __call__(self, x): return x self.W self.b上面这个线性层的实现虽然简单但已经包含了AI工程最核心的几个要素参数初始化、前向计算、以及通过Tensor的自动求导能力支持反向传播。你可以用这个基础组件像搭积木一样堆叠出多层感知机、卷积网络甚至Transformer。4. 训练流程设计让模型真正学起来4.1 损失函数的选择不是拍脑袋损失函数衡量的是模型预测值和真实值之间的差距。回归问题常用均方误差分类问题常用交叉熵。但选择损失函数的时候不能只看任务类型还要考虑数据的分布和模型的输出特性。举个例子如果你做的是二分类模型输出经过Sigmoid之后在0到1之间用二元交叉熵就很合适。但如果你用均方误差梯度在输出接近0或1的时候会变得非常小训练速度会慢得让人抓狂。这是因为Sigmoid函数的导数在两端趋近于零均方误差的梯度再乘上这个趋近于零的导数结果就是梯度消失。交叉熵的好处在于它和Softmax或Sigmoid搭配使用时梯度形式非常简洁就是预测值减去真实值。这个梯度既不会消失也不会爆炸训练起来很稳定。我在手搓损失函数的时候会特意把梯度的推导过程写清楚这样在调试的时候如果发现梯度异常我能快速定位是损失函数的问题还是网络结构的问题。4.2 优化器的迭代逻辑优化器的作用是根据梯度更新参数。最基础的随机梯度下降更新公式是param param - lr * grad。这个公式简单到不能再简单但它有两个明显的缺点一是学习率固定容易在最优解附近震荡二是对所有参数用同一个学习率稀疏特征对应的参数更新不足。为了解决这些问题后来出现了动量法、AdaGrad、RMSProp、Adam等一系列优化器。我的建议是手搓阶段先实现SGD和Adam就够了。SGD帮你理解最基础的更新逻辑Adam帮你理解自适应学习率的思想。Adam的核心在于维护两个移动平均一个是梯度的一阶矩估计一个是二阶矩估计。一阶矩相当于动量让更新方向更平滑二阶矩相当于给每个参数单独调整学习率梯度大的参数学习率小梯度小的参数学习率大。这两个估计都需要一个衰减率来控制历史信息的保留程度通常取0.9和0.999。class Adam: def __init__(self, params, lr1e-3, beta10.9, beta20.999, eps1e-8): self.params params self.lr lr self.beta1 beta1 self.beta2 beta2 self.eps eps self.m [np.zeros_like(p.data) for p in params] self.v [np.zeros_like(p.data) for p in params] self.t 0 def step(self): self.t 1 for i, p in enumerate(self.params): self.m[i] self.beta1 * self.m[i] (1 - self.beta1) * p.grad self.v[i] self.beta2 * self.v[i] (1 - self.beta2) * (p.grad ** 2) m_hat self.m[i] / (1 - self.beta1 ** self.t) v_hat self.v[i] / (1 - self.beta2 ** self.t) p.data - self.lr * m_hat / (np.sqrt(v_hat) self.eps)上面这段Adam的实现里m_hat和v_hat是偏差校正后的估计值。为什么要做偏差校正因为m和v初始化为零在训练初期它们的值会偏向零如果不校正更新步长会异常大。这个细节很多教程都不讲但如果你手搓的时候漏掉了训练初期loss会剧烈震荡。4.3 训练循环中的监控与调优训练循环看起来就是“前向传播、计算损失、反向传播、更新参数”这四步循环但真正写好并不容易。我在实践中会加入几个关键的监控点每个epoch结束后的平均损失、验证集上的准确率、梯度范数、以及参数更新的幅度。梯度范数是一个非常重要的指标。如果梯度范数突然变得很大说明可能遇到了梯度爆炸需要减小学习率或者加梯度裁剪。如果梯度范数一直很小说明可能遇到了梯度消失需要检查网络深度或者激活函数的选择。参数更新幅度则反映了优化器的工作状态如果更新幅度趋近于零说明模型已经收敛或者学习率太小。还有一个容易被忽略的点数据打乱。每个epoch开始前一定要把训练数据随机打乱。如果不打乱模型可能会学到数据的顺序规律而不是真正的特征。我当初做手写数字识别的时候忘了打乱数据结果模型在训练集上准确率很高但在测试集上惨不忍睹排查了好久才发现是这个低级错误。提示在训练循环里加一个简单的早停机制。如果验证集损失连续多个epoch没有下降就提前结束训练。这能帮你节省大量时间也能防止过拟合。5. 推理服务化从实验室到生产环境5.1 模型保存与加载的坑训练好的模型需要保存下来供推理服务使用。保存的时候不能只保存参数还要保存网络结构信息否则加载的时候不知道该怎么重建模型。我习惯用字典的形式保存里面包含模型参数、网络配置、以及训练时的超参数。def save_model(model, path): state { params: [p.data for p in model.parameters()], config: model.config, version: 1.0 } np.savez(path, **state)加载的时候有个坑如果你保存模型时用的NumPy版本和加载时不一致可能会遇到二进制格式不兼容的问题。我的做法是在保存的时候同时记录NumPy版本号加载时先检查版本是否匹配。如果不匹配就尝试用兼容模式加载或者提示用户升级/降级NumPy。另一个坑是参数顺序。如果你保存的时候参数是按层顺序排列的加载的时候也必须按同样的顺序重建网络否则参数会错位。我建议在保存时给每个参数附带一个名字加载时按名字匹配这样即使网络结构有微调也能正确加载大部分参数。5.2 推理性能的优化思路推理服务和训练最大的区别在于推理对延迟敏感对吞吐量有要求。训练的时候你可以慢慢跑推理的时候用户可不会等你。我总结了几个优化方向第一批处理。单条请求推理一次GPU利用率极低。把多条请求攒成一个批次一起推理能大幅提升吞吐量。但批处理会增加单条请求的延迟所以需要根据实际场景权衡批次大小。第二算子融合。把多个连续的小算子合并成一个大的算子减少内存访问次数和内核启动开销。比如把矩阵乘法、偏置加法和激活函数融合成一个算子。这个优化在框架层面通常会自动做但如果你手搓推理引擎就需要自己实现。第三量化。把float32的参数转换成int8模型大小直接缩小四倍推理速度也能提升两到三倍。但量化会带来精度损失需要做校准来最小化影响。我一般会在量化后跑一遍验证集确保精度下降在可接受范围内。第四缓存。对于重复的输入可以直接返回缓存的结果。这个优化在问答系统、推荐系统里特别有效因为很多用户的请求是相似的甚至完全相同的。5.3 服务监控与异常处理推理服务上线之后监控是必不可少的。我重点关注这几个指标请求延迟的P50、P95、P99分位数每秒查询数错误率以及GPU利用率和显存占用。P99延迟特别重要因为它反映了最差情况下的用户体验。如果P99延迟很高说明有少量请求处理特别慢可能是遇到了异常输入或者资源竞争。这时候需要去查日志定位具体是哪些请求出了问题。异常处理方面最常见的问题是输入维度不匹配。用户传进来的数据可能缺少维度、多了维度、或者数据类型不对。我的做法是在服务入口做严格的输入校验不满足要求直接返回错误码而不是让错误渗透到模型内部。模型内部报错往往难以定位而且可能导致服务崩溃。还有一个问题是显存泄漏。如果每次推理都分配新的显存而不释放跑一段时间后显存就会耗尽。Python的垃圾回收机制在这种情况下不一定可靠我建议用显存池来管理预先分配一块显存推理时复用避免频繁的分配和释放。6. 踩坑复盘那些让我熬夜的Bug6.1 梯度消失与梯度爆炸的排查链路梯度消失和梯度爆炸是训练深度学习模型时最常见的两个问题。我遇到过一次典型的梯度爆炸模型训练初期loss正常下降但到某个epoch突然变成NaN。排查过程是这样的第一步检查数据。确认输入数据没有异常值比如无穷大或NaN。数据预处理阶段做了归一化排除了数据问题。第二步检查损失函数。确认损失函数在数值上稳定没有除以零或者取对数时输入为负的情况。第三步检查梯度。在反向传播后打印每一层的梯度范数发现某一层的梯度范数达到了1e8级别确认是梯度爆炸。第四步定位原因。发现是学习率设得太大导致参数更新步长过大进而导致下一轮前向传播的输出爆炸梯度随之爆炸。解决方案是加入梯度裁剪把梯度范数限制在一个阈值以内。同时把学习率降低一个数量级。这两个措施加上之后训练就稳定了。梯度消失的排查思路类似但表现是loss下降极其缓慢甚至完全不下降。这时候需要检查激活函数是否饱和、网络是否过深、以及是否使用了合适的初始化方法。6.2 数据管道中的隐蔽Bug数据管道的问题往往最隐蔽因为代码不报错但模型就是学不好。我遇到过一次模型在训练集上表现正常但在验证集上准确率始终在随机水平附近。排查了很久最后发现是数据加载的时候特征和标签没有对齐。具体来说我用了多线程加载数据但线程之间的数据顺序没有同步导致特征和标签错位。模型学到的是随机噪声自然没有泛化能力。修复方法是给每个数据样本一个唯一的索引加载完成后按索引排序确保特征和标签一一对应。另一个常见问题是数据泄漏。比如在做时间序列预测时如果不小心把未来数据用作了特征模型在验证集上表现会异常好但上线后直接崩盘。我的经验是任何涉及时间的数据都要严格按时间切分训练集和验证集绝不能随机切分。6.3 推理服务的并发陷阱推理服务上线后我遇到过一次并发问题单条请求测试正常但并发量一上来服务就卡死。排查后发现是全局锁的问题。我在模型推理的代码里加了一个锁来保护共享资源但锁的粒度太大导致所有请求串行执行。解决方案是把锁的粒度缩小只保护真正需要互斥的部分。对于模型推理来说如果模型参数是只读的其实不需要加锁。多个线程可以同时读取同一份参数只要没有写入操作。我把参数加载和推理分离加载时加锁推理时不加锁并发性能直接提升了十几倍。还有一个坑是Python的GIL。在多线程环境下Python的全局解释器锁会导致CPU密集型任务无法真正并行。对于推理服务如果瓶颈在CPU计算上多线程反而可能比单线程更慢。这时候应该用多进程或者把计算密集的部分用C扩展实现。7. 从手搓到工程化的进阶路线手搓一遍之后你对AI系统的理解已经超过了大多数只会调包的人。但手搓的代码毕竟性能有限真正上生产环境还是需要借助成熟的框架和工具。我的建议是手搓是为了理解原理工程化是为了提升效率两者不矛盾。进阶的第一步是把你的手搓代码和PyTorch或TensorFlow的实现做对比。同样的网络结构同样的数据看看框架的实现和你的实现在数值上是否一致。如果不一致去查框架的源码看看它做了什么额外的优化。这个过程能让你学到很多工程技巧。第二步学习分布式训练。单机单卡的训练能力有限当模型大到一定程度必须用多卡甚至多机来训练。分布式训练涉及数据并行、模型并行、流水线并行等策略每种策略的通信开销和适用场景都不同。这部分内容比较复杂建议先从数据并行入手理解梯度同步的机制。第三步了解模型压缩和加速技术。除了前面提到的量化还有剪枝、知识蒸馏、低秩分解等方法。这些技术能让你在保持模型精度的同时大幅降低推理成本。我在实际项目中通常会把量化作为首选方案因为它的实现相对简单效果也比较稳定。第四步构建完整的MLOps流水线。包括数据版本管理、实验跟踪、模型注册、自动化部署、线上监控等环节。这部分内容偏向工程管理但它是AI项目从Demo走向产品的必经之路。我见过太多团队模型训得很好但因为没有好的工程化支撑最后无法落地。提示不要试图一次性把所有东西都学会。AI工程是一个很大的领域先把手搓这条线走通建立起核心认知然后再根据实际工作需要有针对性地深入某个方向。8. 一些掏心窝子的实操建议最后分享几个我在这个过程中总结的经验都是踩过坑之后才明白的。关于调试不要一上来就用复杂的模型和数据。先用一个极简的模型和几条假数据确保整个训练流程能跑通损失能下降。然后再逐步替换成真实数据和真实模型。这样出问题的时候排查范围小定位快。关于性能不要过早优化。先让代码跑起来再让它跑得对最后才让它跑得快。我见过很多人一上来就追求极致的性能结果代码复杂到连自己都看不懂出了问题根本没法调。关于学习手搓一遍的价值不在于你以后要自己写框架而在于你以后用框架的时候知道它底层在干什么。当框架报了一个奇怪的错误你能猜到大概是哪个环节出了问题当模型表现不符合预期你能从原理层面分析可能的原因。这种能力是看多少篇教程都换不来的。关于心态手搓的过程一定会遇到很多挫折梯度不下降、维度对不上、数值溢出这些都是家常便饭。我当初实现自动求导的时候前后改了十几版才跑通。但每次解决一个问题你对系统的理解就深一层。这种积累是任何捷径都替代不了的。如果你也在走这条路我的建议是别急慢慢来。把每个模块都亲手实现一遍把每个Bug都亲手排查一遍。这个过程很慢但走完之后你就不再是那个只会调包的“AI应用工程师”而是一个真正理解AI系统运转原理的工程师。这两者之间的差距在遇到复杂问题的时候会体现得淋漓尽致。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Atlas材料参数与物理模型:从能跑通到跑得准的仿真标定指南 2026/9/29 4:38:46

Atlas材料参数与物理模型:从能跑通到跑得准的仿真标定指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
YOLOv8+PyQt5水稻害虫检测:自建数据集训练到桌面部署 2026/9/29 4:38:46

YOLOv8+PyQt5水稻害虫检测:自建数据集训练到桌面部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
xberg Dart 爬虫提取实战:使用 crawl 模式跟随链接批量抽取网页内容 2026/9/29 4:38:46

xberg Dart 爬虫提取实战:使用 crawl 模式跟随链接批量抽取网页内容

后端AI 应用NLP 【免费下载链接】xberg Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with …

阅读更多 →
基于STM32单片机无线鼠标电脑USB有线鼠标蓝牙通信接收器蓝牙无线APP/WiFi无线APP-DIY设计S510 2026/9/29 4:38:46

基于STM32单片机无线鼠标电脑USB有线鼠标蓝牙通信接收器蓝牙无线APP/WiFi无线APP-DIY设计S510

S510-鼠标USB接电脑摇杆上下左右移动光标左键右键滚动电源蓝牙/WiFi/视频监控/云平台APP本系统由STM32F103C8T6单片机核心板、无线蓝牙/WIFI/视频监控/云平台模块-可选、USB口、鼠标部分、MPU6050模块、电源电路组成。【1】鼠标设计分USB版、蓝牙通信版、WIFI通信版。实际蓝牙版…

阅读更多 →
告别付费与隐私泄露!一套功能全面的 PDF 工具! 2026/9/29 4:38:39

告别付费与隐私泄露!一套功能全面的 PDF 工具!

大家好,我是 Java陈序员。 在日常办公学习中,离不开与 PDF 打交道,合并 PDF、压缩大小、拆分页面、格式转换…… 但现在的在线 PDF 工具,要么广告满天飞、弹窗不断;要么限制免费次数、强行加水印;最致命的是…

阅读更多 →
基于STM32单片机编码器电机减速电机PID控制温度PWM调速蓝牙/WiFi/视频监控/云平台无线APP-DIY设计S458 2026/9/29 4:38:39

基于STM32单片机编码器电机减速电机PID控制温度PWM调速蓝牙/WiFi/视频监控/云平台无线APP-DIY设计S458

S458-编码器电机测速电机驱动温度超速高温报警PID控制PWM10档加减速正反转电源OLED屏声光提醒按键蓝牙/WiFi/视频监控/云平台APP本系统由STM32F103C8T6单片机核心板、OLED屏、无线蓝牙/WIFI/视频监控/云平台模块-可选、电压转换、电机驱动电路、直流无刷电机接口、防水温度检测…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉