四只称重传感器并联后怎样校准角差

2026-11-021

同一块热床,在左前角放一个砝码与在右后角放同一个砝码,读数却不一样。把空床重新去皮,两个位置的差异仍在。

这时先别急着提高滤波强度。四只称重传感器共用一个 ADC,接线图看起来对称,电气上的贡献却未必相同。去皮能减掉当前零点,不能自动补偿各个支点的灵敏度。

下面把问题缩到可以算清、可以复核的范围。四个四线全桥共用 4 V 激励,输出并到 ADS1220 的 AIN0、AIN1,每路正输出串一个 20 Ω 电位器。我们要回答三个问题:并联后到底测到了什么,电位器能补多少,怎样判断调节已经越界。

四桥并联的直流等效示意

图1 直流等效示意。磁珠及 ADC 输入滤波不画在这张简图内;四个桥共用一组差分输入。

先找清楚电位器调在哪里

实际工程里,四个接口是 U2、U3、U4、U8。每个接口的1脚经磁珠和 R1~R4 进入公共 AIN0,2脚经磁珠进入公共 AIN1,3脚接地,4脚接 +4 V。

R1~R4 标注 20 Ω,使用滑臂和一个固定端,另一端未接。因此,它们是信号正端的串联微调,不能按“激励电压调节器”理解。也不要按线色猜接法,线色与桥的极性必须以所用传感器的资料为准。

四路桥输出与20欧微调的实际EDA局部

图2 实际 EDA 总装配图局部。左侧公共走线分别连接 AIN0、AIN1、GND 和 +4 V;每组只有一条信号线经过电位器。

一个容易混淆的阻值是“350 Ω”。对四个桥臂均为 350 Ω 的理想全桥,输出正端到交流等效地的电阻是 350∥350 = 175 Ω,负端也一样;差分输出电阻才是两者之和 350 Ω。后面的例子用每个半桥 175 Ω,不能把传感器标称的差分输出电阻直接填进两边。

实际桥臂不等、线阻不等时,应分别取得正负半桥等效电阻。先断电、断开并联网络再测量,不能把四桥并起来的读数当成单只传感器参数。

并联是加权平均,换算后才可能得到总力

在小信号、静态、高输入阻抗的条件下,将第 i 个全桥写成两个戴维南源。未加载时,两端电压分别是 E/2 + e_i/2 与 E/2 - e_i/2,其中 E 为激励电压,e_i 为该桥开路差分电压。

设正、负半桥输出电阻为 rp_i、rn_i,正端微调为 t_i。公共正端的电压取决于每一路电导 1/(rp_i+t_i),公共负端则取决于 1/rn_i。把两侧电导分别归一化为 wp_i、wn_i,便有:

Vdiff = Σ α_i·e_i,其中 α_i = (wp_i+wn_i)/2。

四个 α 的和是1。四只相同的桥不加微调时,每个 α 为1/4。因此,相同传感器单独承受10 N得到的差分信号,并联后只贡献其四分之一。系统可以通过标定把它换算为总力,但 ADC 没有直接把四个电压相加。

再写成 e_i = z_i + s_i·F_i,z 是零点,s 是灵敏度,F 是该桥承受的力。去皮后剩下 Σ α_i·s_i·F_i。只有四个 α_i·s_i 相等,力从一个支点转移到另一个支点时,读数才不因电气权重而改变。

这也说明,一条总信号不能还原四只桥各自的受力。想同时得到四角力或判断某一只桥断线,需要额外的独立通道或诊断电路。

20 Ω 的调节范围并不大

取四个半桥电阻均为175 Ω,仅把第一路正端串阻从0调到20 Ω。它的正侧权重从0.25降到约0.230263,负侧权重仍为0.25,合成权重因此降到约0.240132。

相对原来的0.25,该路贡献只下降约3.95%。同时另外三路各增加约1.32%。这些数是此模型的计算结果,不是所有称重传感器都适用的标称能力。

也就是说,一边拧一个电位器,其他角的比例也会跟着变。遇到很大的角差,应该先查支点是否有力旁路、传感器受力方向是否一致、是否存在预紧和线缆拉扯,再考虑配平。不能指望20 Ω包办所有机械误差。

匹配后的零点也可能改变。电位器改变了 z_i 的加权方式;每次调节以后,需要重新去皮并复核增益,而不是沿用之前的零点和标定系数。

把调节目标算出来,再决定能不能做

令四个去皮后的力系数都等于 c。由于正负两侧的归一化权重各自相加为1,可以推得:

c = 1/Σ(1/s_i),wp_i = 2c/s_i - wn_i。

计算出的正侧目标权重必须大于0。再把各路正侧电导设成 λ·wp_i,就能反求串阻 t_i = 1/(λ·wp_i) - rp_i。选择使所有串阻非负的最大 λ,能让至少一路串阻为0,同时让其余所需串阻尽量小。任何一路仍超过20 Ω,就应明确判定超范围。

下面的完整工具只用 Python 标准库。保存为 bridge_trim.py,用 Python 3.12 执行 python bridge_trim.py。输入灵敏度单位为 μV/N,输出电阻单位为 Ω;示例数据是合成输入。它不访问串口、不控制 Z 轴,也不修改 Klipper 配置。

"""Four full bridges, one positive-output trim per bridge. Python 3.12, stdlib."""
from math import fsum, isfinite


def four(values, name, positive=False):
    out = tuple(float(x) for x in values)
    if len(out) != 4 or not all(isfinite(x) for x in out):
        raise ValueError(name + " needs four finite values")
    if positive and not all(x > 0 for x in out):
        raise ValueError(name + " must be positive")
    return out


def weights(rp, rn, trim):
    rp, rn = four(rp, "rp", True), four(rn, "rn", True)
    trim = four(trim, "trim")
    if min(trim) < 0:
        raise ValueError("negative trim")
    gp = tuple(1 / (r + t) for r, t in zip(rp, trim))
    gn = tuple(1 / r for r in rn)
    return tuple((p / fsum(gp) + n / fsum(gn)) / 2
                 for p, n in zip(gp, gn))


def plan_trim(rp, rn, sensitivity, limit=20.0):
    rp, rn = four(rp, "rp", True), four(rn, "rn", True)
    s = four(sensitivity, "sensitivity", True)
    limit = float(limit)
    if not isfinite(limit) or limit < 0:
        raise ValueError("invalid trim limit")
    gn = tuple(1 / r for r in rn)
    wn = tuple(g / fsum(gn) for g in gn)
    common = 1 / fsum(1 / x for x in s)
    wp = tuple(2 * common / x - n for x, n in zip(s, wn))
    if min(wp) <= 0:
        raise ValueError("one-sided trim cannot match these bridges")
    scale = min(1 / (r * w) for r, w in zip(rp, wp))
    trim = tuple(max(0.0, 1 / (scale * w) - r)
                 for r, w in zip(rp, wp))
    if max(trim) > limit + 1e-9:
        raise ValueError("required trim exceeds limit")
    return trim


def output_uv(rp, rn, trim, sensitivity, force_n, offset_uv):
    s = four(sensitivity, "sensitivity", True)
    f = four(force_n, "force_n")
    z = four(offset_uv, "offset_uv")
    return fsum(w * (b + k * load) for w, b, k, load in
                zip(weights(rp, rn, trim), z, s, f))


def corner_uv(rp, rn, trim, s, force=10.0):
    # Tared response to a force carried entirely by one bridge.
    return tuple(w * k * force for w, k in
                 zip(weights(rp, rn, trim), s))


if __name__ == "__main__":
    rp = rn = (175.0,) * 4  # Half-bridge Thevenin resistance, ohm.
    s = (200.0, 204.0, 198.0, 202.0)  # Synthetic uV/N, not measurements.
    trim = plan_trim(rp, rn, s)
    before = corner_uv(rp, rn, (0.0,) * 4, s)
    after = corner_uv(rp, rn, trim, s)
    for label, values in (("trim_ohm", trim),
                          ("before_uV", before), ("after_uV", after)):
        print(label, " ".join(f"{x:.6f}" for x in values))
    z = (6.0, -4.0, 9.0, -3.0)
    for t in ((0.0,) * 4, trim):
        print("zero_uV", f"{output_uv(rp, rn, t, s, (0,)*4, z):.6f}")
    try:
        plan_trim(rp, rn, (200, 240, 198, 202))
    except ValueError as exc:
        print("rejected_example", exc)

例子中,四个 s 分别为200、204、198、202 μV/N。它们对应的理论微调为3.518283、10.768132、0、7.106949 Ω。相同10 N分别由一个桥承担时,去皮输出从500、510、495、505 μV,变成四个相同的约502.437806 μV。

相同载荷在四个支点的模型输出对比

图3 合成数据的直流计算。纵轴从470 μV开始,以便观察角差;柱形接近并不代表已完成真实热床标定。

四个桥的零点若设为6、−4、9、−3 μV,配平前总零点为2.000000 μV,配平后约为2.059755 μV。程序还会拒绝将第二只桥灵敏度改成240 μV/N的例子,因为所需串阻超过20 Ω。

校验没有只用同一公式自证。另建由电阻组成的六节点网络,通过节点电流方程求解200组随机桥参数,再与工具输出比对,最大差异约 4.98×10^-8 μV。同时检查100组随机受力分配,在总力相同且已匹配的模型里输出一致;超范围、非正灵敏度、非有限数、数量错误、负调节范围和负串阻六类输入均被拒绝。这证明的是模型与程序的一致性,不是传感器精度。

实际使用时,s 和半桥电阻必须来自对应传感器的可靠参数或独立测量。若无法分离电气误差与机械分配,就不要把这组理论串阻当成现场调节指令。

ADC 接上了,参考源也要选对

这版 ADS1220 电路的 AVDD 为 +4 V,DVDD 为 +3.3 V。TSSOP16 封装中,AIN0 是11脚、AIN1是10脚;REFP0 是9脚并接 +4 V,REFN0 是8脚并接地。两路输入各串100 Ω,芯片侧有100 nF差分电容。

ADS1220模拟输入和参考电压的实际EDA局部

图4 实际 EDA 的 ADS1220 局部。此处展示的是原电路连接,不表示现有固件已经选择外部参考。

桥激励与参考同源,为比率式测量提供了硬件条件,但寄存器还必须匹配。TI 手册中,配置寄存器2的 VREF 位为 01b 才选择专用 REFP0/REFN0,复位值 00b 选择内部2.048 V。不能照搬另一张应用图的寄存器值,因为另一图可能使用 AIN0/REFP1 和 AIN3/REFN1。

参考源也不能消除角差。它主要抵消同源激励变化的影响,不会让不同 s_i 自动相等,无法消除各路不同的线损和机械力旁路。

还要区分 ADC 数字满量程与 PGA 线性范围。以 AVDD=4 V、AVSS=0 V、共模约2 V、增益128为例,数字满量程为约±31.25 mV;按 PGA 两端各留0.2 V的限制,差分信号应先满足约±28.125 mV以内,并同时核对共模下限和实际最大信号。传感器零点偏移也占用这部分余量。

PCB 上能检查什么,台架上还缺什么

同版PCB顶面铜层与丝印

图5 同版 PCB 顶面观察,显示顶层铜、顶层丝印、板框与多层焊盘。

同版PCB底面铜层与丝印

图6 同版 PCB 底面观察,显示底层铜、底层丝印、板框与多层焊盘;图像已按底面方向导出。

顶底面对照,可以追踪四组桥线如何汇总,以及 AIN0、AIN1 如何进入 ADC 周边。检查时保留差分两线的对应关系,别让长线在热床加热器、风扇或电机回路附近各走各的。磁珠和输入电容也不能替代正确布线。

真正的台架复核,建议先固定装配与温度条件,用同一个已知载荷依次放在四个规定位置,记录去皮前零点、去皮后增量、撤载回零与重复性;每次位置切换都保留原始样本,不只抄滤波后的一个数。调节后重新去皮、重新做总增益标定,再重复四角试验,并在不同载荷和热床工作温度下复核。

若载荷离开后不回零,先排查蠕变、摩擦和安装应力;若四角差随温度变化,就不能只在冷床校一次。若更换参数仍无法将理论串阻控制在范围内,应改用参数更接近的传感器、适当的桥路接线盒,或多通道独立采集方案。

本文完成的是并联桥路的直流模型、配平求解与独立电阻网络核验。没有进行传感器实体测量、ADC 固件烧录、整机 ERC/DRC 或打印机动作测试,因此这些结果不能直接作为归零、碰撞保护或安全限位的依据。先把“同一个力为何读出不同数字”解释清楚,才有继续做自动调平的基础。

资料与验证范围

工程与 EDA 图来自 LAFUMA2012 的《3D打印机_Klipper(原生)热床称重调平方案ADS1220》,按项目标注的 OpenAtom OHL 1.0 使用,必要归属保留。工程入口 https://oshwhub.com/lafuma2012/klipper-re-chuang-chen-zhong-diao-ping-fang-an ,实际设计入口 https://pro.lceda.cn/editor#id=25fdc59adca84179b098c0feb31ccb3c 。核对版本为图页 V1.0、总装配图更新2026-02-07,项目页更新2026-07-29;本次从实际编辑器重新导出原理图 SVG 和4096像素宽 PCB 顶底面,仅裁剪留白、保真缩放,未改动连线。

ADS1220 参数依据 TI《SBAS501D》Rev. D 的引脚、PGA 共模、参考源及桥式测量章节,官方资料 https://www.ti.com/document-viewer/ADS1220/datasheet 。图1、图3、推导及 bridge_trim.py 为本文独立完成,程序版本1.0.0;计算采用理想同源激励、固定半桥阻抗及高输入阻抗,忽略磁珠直流电阻、ADC 输入电流与动态滤波,全部结果为合成输入验证。

技术交流,欢迎关注微信公众号:美男子玩编程。

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -