<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ODrive on sunjiyi&#39;s Blogggg</title>
        <link>https://a233a2.github.io/tags/odrive/</link>
        <description>Recent content in ODrive on sunjiyi&#39;s Blogggg</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>Sunjiyi Make and Design</copyright>
        <lastBuildDate>Mon, 10 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://a233a2.github.io/tags/odrive/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>抗齿槽转矩算法的一次实现(Cogging Compensation)</title>
        <link>https://a233a2.github.io/p/%E6%8A%97%E9%BD%BF%E6%A7%BD%E8%BD%AC%E7%9F%A9%E7%AE%97%E6%B3%95%E7%9A%84%E4%B8%80%E6%AC%A1%E5%AE%9E%E7%8E%B0cogging-compensation/</link>
        <pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate>
        
        <guid>https://a233a2.github.io/p/%E6%8A%97%E9%BD%BF%E6%A7%BD%E8%BD%AC%E7%9F%A9%E7%AE%97%E6%B3%95%E7%9A%84%E4%B8%80%E6%AC%A1%E5%AE%9E%E7%8E%B0cogging-compensation/</guid>
        <description>&lt;p&gt;先来看实现低速跟踪效果，同一组PID参属下的两种形式：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:center&#34;&gt;关闭齿槽转矩补偿&lt;/th&gt;
&lt;th style=&#34;text-align:center&#34;&gt;开启齿槽转矩补偿&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://a233a2.github.io/p/%E6%8A%97%E9%BD%BF%E6%A7%BD%E8%BD%AC%E7%9F%A9%E7%AE%97%E6%B3%95%E7%9A%84%E4%B8%80%E6%AC%A1%E5%AE%9E%E7%8E%B0cogging-compensation/%E5%85%B3%E9%97%AD%E8%A1%A5%E5%81%BF.png&#34;
	width=&#34;838&#34;
	height=&#34;1234&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;关闭齿槽转矩补偿&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;67&#34;
		data-flex-basis=&#34;162px&#34;
	
&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:center&#34;&gt;&lt;img src=&#34;https://a233a2.github.io/p/%E6%8A%97%E9%BD%BF%E6%A7%BD%E8%BD%AC%E7%9F%A9%E7%AE%97%E6%B3%95%E7%9A%84%E4%B8%80%E6%AC%A1%E5%AE%9E%E7%8E%B0cogging-compensation/%E5%BC%80%E5%90%AF%E8%A1%A5%E5%81%BF.png&#34;
	width=&#34;840&#34;
	height=&#34;1231&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;开启齿槽转矩补偿&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;68&#34;
		data-flex-basis=&#34;163px&#34;
	
&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id=&#34;给-foc-加上抗齿槽转矩一次从原地抖动到成功标定的实践&#34;&gt;给 FOC 加上抗齿槽转矩：一次从“原地抖动”到成功标定的实践
&lt;/h1&gt;&lt;p&gt;最近在 P-NUCLEO-IHM03、MS4015 云台电机和 MT6701 磁编码器组成的 FOC 平台上，因为前期写完了FOC驱动代码，电流环性能调的非常好了已经，但是&lt;strong&gt;低速控制下速度环参数不知道什么问题整定一直没调好&lt;/strong&gt;，故引入了一套抗齿槽转矩的功能，实测对低速下的优化效果非常不错，故分享一下。&lt;/p&gt;
&lt;h2 id=&#34;为什么要做抗齿槽转矩补偿&#34;&gt;为什么要做抗齿槽转矩补偿
&lt;/h2&gt;&lt;p&gt;永磁电机在低速运行时，常能感觉到转子在某些角度更容易停住。这种与机械角度相关的周期性转矩，会带来一些典型问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;低速运行不均匀；&lt;/li&gt;
&lt;li&gt;速度环容易出现周期性波动；&lt;/li&gt;
&lt;li&gt;位置环在目标附近轻微振荡；&lt;/li&gt;
&lt;li&gt;为克服局部阻力而提高积分后，又容易发生过冲。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;单纯继续提高 PI 或 PD 参数通常不能真正解决问题，因为&lt;strong&gt;齿槽转矩是一种与转子位置相关、可重复出现的扰动。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;更合适的方法是&lt;strong&gt;提前学习这种扰动，然后根据转子的机械角度增加一个补偿电流&lt;/strong&gt;，也就是前馈补偿：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;最终 Iq = 闭环控制器输出 + 当前角度对应的前馈补偿
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;闭环控制器继续负责稳定和纠正误差，查表前馈则负责提前抵消周期性的齿槽转矩。查表法也是一种工程上被最广泛使用的方法吧，抑制齿槽转矩其实还有更好的方案，例如使用数学方法，如谐波函数补偿，学术界更是有很多牛上天的方法，但是此处就先使用工程上被验证过多次的查表法。&lt;/p&gt;
&lt;h2 id=&#34;算法设计来源&#34;&gt;算法设计来源
&lt;/h2&gt;&lt;p&gt;主要思路参考了 ODrive 开源固件中的 Anticogging 功能。&lt;/p&gt;
&lt;p&gt;ODrive 的基本思想是：让电机依次到达一圈内的各个位置，记录维持该位置所需要的转矩，然后生成一张与机械角度对应的补偿表。正常运行时，再根据编码器角度查表并叠加前馈。&lt;/p&gt;
&lt;p&gt;本项目同样采用了 3600 个采样点，也就是每 0.1° 一个补偿值。&lt;/p&gt;
&lt;p&gt;不过，我最终没有完全照搬“每个位置停稳后采样”的运动方式。原因是不同电机和机械系统的摩擦特性差别很大，适合 ODrive 原始应用场景的方法，并不一定能直接用于当前电机。&lt;/p&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/odriverobotics/ODrive&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ODrive 官方仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/odriverobotics/ODrive/blob/master/Firmware/MotorControl/controller.cpp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ODrive 控制器源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://blog.csdn.net/loop222/article/details/134847403&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CSDN 参考文章&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://zhuanlan.zhihu.com/p/1936345470315242384&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;知乎参考文章&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;最终方案低速连续扫描&#34;&gt;最终方案：低速连续扫描
&lt;/h2&gt;&lt;p&gt;最终采用的是低速、单方向、连续扫描一整圈：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用一套独立且比较保守的速度控制器；&lt;/li&gt;
&lt;li&gt;缓慢增加驱动电流，让电机平稳克服静摩擦；&lt;/li&gt;
&lt;li&gt;确认电机已经连续转动后，再锁定正式扫描起点；&lt;/li&gt;
&lt;li&gt;让电机以很低的速度单方向旋转一整圈；&lt;/li&gt;
&lt;li&gt;每经过一个 0.1° 区间，就记录该区间内的平均 q 轴电流；&lt;/li&gt;
&lt;li&gt;完成 3600 点后停止电机并保存结果；&lt;/li&gt;
&lt;li&gt;正常运行时，根据 MT6701 的单圈角度查表并进行插值。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;flowchart LR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    A[&amp;#34;缓慢起转&amp;#34;] --&amp;gt; B[&amp;#34;确认连续运动&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    B --&amp;gt; C[&amp;#34;低速扫描一圈&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    C --&amp;gt; D[&amp;#34;按角度区间记录平均 Iq&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    D --&amp;gt; E[&amp;#34;去除整表平均值&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    E --&amp;gt; F[&amp;#34;保存补偿表&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    F --&amp;gt; G[&amp;#34;运行时查表前馈&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;连续扫描不再要求电机精确停在每个 0.1° 目标点，因此绕开了最容易发生粘滑振荡的工作状态。&lt;/p&gt;
&lt;p&gt;为了避免电机在扫描过程中再次正反抖动，还加入了几个保护思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;驱动电流缓慢建立；&lt;/li&gt;
&lt;li&gt;减小电流时可以更快，但反向制动力受到严格限制；&lt;/li&gt;
&lt;li&gt;控制器包含抗积分饱和；&lt;/li&gt;
&lt;li&gt;只有确认电机已经连续起转，才开始正式记录数据；&lt;/li&gt;
&lt;li&gt;如果长时间没有新的角度进度，就自动停止并报告失败。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;为什么要对补偿表去均值&#34;&gt;为什么要对补偿表去均值
&lt;/h2&gt;&lt;p&gt;连续单方向旋转时，测得的电流不仅包含齿槽转矩，还包含轴承摩擦和其他近似恒定的负载。&lt;/p&gt;
&lt;p&gt;如果直接保存，就会在所有角度都附加一个固定方向的电流，这并不是我们想要的结果。&lt;/p&gt;
&lt;p&gt;因此完成一圈采样后，需要先计算整张表的平均值，再让每个采样点减去这个平均值：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;最终补偿值 = 原始采样值 - 全部采样点的平均值
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样可以去掉大部分恒定摩擦和直流偏置，保留随角度周期变化的部分。&lt;/p&gt;
&lt;p&gt;严格来说，这张表学习到的不一定只有纯粹的齿槽转矩。磁铁偏心、编码器安装误差和位置相关摩擦等可重复扰动，也可能被记录进去。但只要这些扰动与机械角度稳定对应，查表前馈仍然能够改善实际控制效果。&lt;/p&gt;
&lt;h2 id=&#34;最终效果&#34;&gt;最终效果
&lt;/h2&gt;&lt;p&gt;改成连续扫描后，电机不再停留在第一个点正反抖动，而是能够平稳地完成一整圈标定，并自动保存补偿结果。&lt;/p&gt;
&lt;p&gt;实际启用补偿后，低速和位置控制效果有了明显改善。这也说明查表前馈的方向是有效的，而最初失败的主要原因并不是算法思想错误，而是采集方式没有适配这台电机的静摩擦特性。&lt;/p&gt;
&lt;h2 id=&#34;这次调试得到的经验&#34;&gt;这次调试得到的经验
&lt;/h2&gt;&lt;h3 id=&#34;1-不要只照搬算法流程&#34;&gt;1. 不要只照搬算法流程
&lt;/h3&gt;&lt;p&gt;同一个算法在不同电机、轴承、负载和编码器结构上，可能需要完全不同的标定运动方式。应保留核心思想，同时根据真实机械特性调整实现。&lt;/p&gt;
&lt;h3 id=&#34;2-电机抖动不一定是增益太小&#34;&gt;2. 电机抖动不一定是增益太小
&lt;/h3&gt;&lt;p&gt;当电流已经频繁达到正负限幅时，继续提高 Kp 或 Ki 往往只会让抖动更激烈。此时应检查控制结构是否已经变成近似的正反开关控制。&lt;/p&gt;
&lt;h3 id=&#34;3-静摩擦是低速标定的重要限制&#34;&gt;3. 静摩擦是低速标定的重要限制
&lt;/h3&gt;&lt;p&gt;如果目标位移小于突破静摩擦后的自然位移，逐点定位就很难稳定。连续扫描通常比反复停止更适合这种系统。&lt;/p&gt;
&lt;h3 id=&#34;4-诊断数据比主观观察更可靠&#34;&gt;4. 诊断数据比主观观察更可靠
&lt;/h3&gt;&lt;p&gt;同时观察目标位置、实际位置、速度和 Iq，可以快速判断究竟是方向错误、编码器异常，还是控制器饱和。&lt;/p&gt;
&lt;h3 id=&#34;5-前馈补偿不能替代闭环&#34;&gt;5. 前馈补偿不能替代闭环
&lt;/h3&gt;&lt;p&gt;抗齿槽表只是帮助闭环控制器减轻周期扰动，电流环、速度环和位置环本身仍然必须保持稳定。启用补偿后，也应该重新检查外环是否需要小幅调整。&lt;/p&gt;
&lt;h2 id=&#34;结语&#34;&gt;结语
&lt;/h2&gt;&lt;p&gt;这次实现最重要的改进，不是找到了一组更大的控制参数，而是把标定方式从“每隔 0.1° 停下来”改成了“低速连续扫描”。&lt;/p&gt;
&lt;p&gt;核心经验可以概括为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当控制器无法在极小位置步长上战胜静摩擦时，不要继续强行提高增益；换一种不需要反复突破静摩擦的采集方式，往往更有效。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最终保留了 ODrive 查表前馈的核心思想，又针对当前电机的实际特性完成了适配。这也正是开源算法落地到真实硬件时最有价值的部分。&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
