一条装配线二十颗螺丝,工人少打一颗,整机到了客户端才发现异响——整批召回。更隐蔽的是:螺丝都打了,但有一颗扭矩只有设定值的一半(浮锁),有一颗打了两次(重复拧把螺纹拧滑),还有人拿错了程序号,M4 的螺丝用了 M6 的扭矩。普通电批只认"扳机会不会响",智能拧紧工位要解决的是三个问题:每一颗都打了、每一颗都达标、每一颗都能追到是哪件产品哪个人哪把刀

一、拧紧工具三档:先按质量等级选,别上来就买拧紧轴

档位典型工具上位机能拿到什么适用场景
普通电批/风批定扭离合式,靠机械打滑控制扭矩什么都拿不到,最多加个计数器夹头输出脉冲家电外壳等无扭矩追溯要求的场合
计数器电批电批 + 螺丝计数器(SCREW COUNT)24V 脉冲:OK/NG、批次完成 BatchDone、可配程序号选择位只防漏拧、不关心扭矩值的工位,成本低
智能拧紧轴带电流/扭矩传感器的数控电批或伺服拧紧轴(阿特拉斯/马头/国产 QMC 等)扭矩值、角度值、OK/NG、程序号、时间戳、扭矩曲线,串口或以太网开放协议汽车零部件、电池包、安全件,必须扭矩追溯

三档的成本差距是数量级的,选型只看一条:客户端图纸/质量协议里有没有扭矩记录要求。有 Cmk、扭矩追溯条款的只能上第三档;只要求"颗数不少"的,计数器电批加 PLC IO 就够,多花的钱不如花在治具定位上。

二、拧紧策略基础:扭矩、角度和那条曲线

策略控制量说明
扭矩法 T目标扭矩 + 上下限最常用。拧紧到目标扭矩即停,受摩擦系数影响大,夹紧力散差约 ±25%
扭矩-转角法 TA先拧到贴合扭矩,再转固定角度汽车安全件主流。夹紧力由角度段塑性拉长保证,散差可压到 ±10% 以内
屈服点法 Y实时监测扭矩斜率,到屈服点停夹紧力最一致但对螺栓一致性要求高,多用于发动机连杆等关键部位

一次拧紧结果里,上位机至少要拿到这四样,缺一样追溯链就是断的:

测量扭矩8.62 N·m
测量角度42.3°
程序号 Pset#012 M5-8Nm
时间戳/刀号09-18 14:22:07 / GUN-03
OK 不是一个布尔量那么简单。控制器给出的总 OK 同时包含:扭矩在窗口内、角度在窗口内、方向对、没有提前打滑、没有超时。上位机不要只存总状态,分项状态字也要存——客户投诉时"扭矩高报"和"角度低报"指向的工艺整改方向完全不同(前者查摩擦/扭矩设定,后者查浮锁/垫片漏装)。

三、两种接法:24V IO 简单可靠,OpenProtocol 拿全数据

对比项IO 方式(计数器/控制器IO)OpenProtocol 以太网(主流控制器)
物理接口控制器 IO 端子 → PLC 输入输出点控制器网口 → 车间交换机,TCP 长连接(默认 4545 端口)
拿到的数据OK/NG、批次完成、批次计数扭矩/角度/分项状态/程序号/VIN/SN/曲线号,全字段
切换程序号二进制选择位(3~4 个输入点编 8~16 个号),置位后给选通脉冲上位机发 MID 0018 选择参数集命令,控制器回 MID 0019
与产线联锁工具使能、放行信号全部走 PLC,硬接线实时业务数据走上位机,安全联锁仍建议走 PLC,不要让电脑死机锁住产线安全逻辑
开发成本低,PLC 点表 + 上位机读 DB/Modbus中,要实现协议栈或用厂商 SDK(部分厂商提供 .NET 库)

OpenProtocol 是汽车行业拧紧控制器事实上的开放协议,报文是定长 ASCII,前 20 个字符是帧头:长度 4 位、MID 4 位、版本 3 位、NoAck 标志 1 位、工位号 2 位、轴号 2 位、保留 4 位,后面才是数据区。典型交互:连接后发 MID 0001 建立通信,控制器回 MID 0002;按手册发送订阅命令后,每完成一次拧紧控制器主动推送 MID 0061(单轴最后一次拧紧结果);空闲时双方互发 MID 9999 心跳。

public class OpenProtocolClient : IDisposable
{
    private TcpClient _tcp;
    private NetworkStream _ns;
    private readonly byte[] _buf = new byte[4096];
    private string _carry = "";

    public event Action<TighteningResult> TighteningReceived;

    public async Task ConnectAsync(string ip, int port = 4545)
    {
        _tcp = new TcpClient { ReceiveTimeout = 10000 };
        await _tcp.ConnectAsync(ip, port);
        _ns = _tcp.GetStream();
        await SendAsync("002000010010...");   // MID 0001 建立通信(后补工位/控制器约定字段)
        await SendAsync(BuildSubscribe(61));   // 订阅 0061,具体订阅MID按该控制器版本手册
        _ = ReceiveLoopAsync();
    }

    private async Task ReceiveLoopAsync()
    {
        while (_tcp.Connected)
        {
            int n = await _ns.ReadAsync(_buf, 0, _buf.Length);
            if (n <= 0) break;
            _carry += Encoding.ASCII.GetString(_buf, 0, n);

            // 粘包拆包:每帧前4字符即本帧总长,可能一次收半帧或两帧
            while (_carry.Length >= 20 &&
                   int.TryParse(_carry.Substring(0, 4), out var len) && _carry.Length >= len)
            {
                var frame = _carry.Substring(0, len);
                _carry = _carry.Substring(len);
                Dispatch(frame);
            }
        }
    }

    private void Dispatch(string frame)
    {
        var mid = frame.Substring(4, 4);
        switch (mid)
        {
            case "0002": break;                 // 通信建立确认
            case "0061": TighteningReceived?.Invoke(Parse0061(frame)); break;
            case "9999": _ = SendAsync("00209999            "); break; // 心跳回送
        }
    }
}
定长协议的两个坑。一是字段位置随 MID revision(版本号)变化,同一台控制器升级固件后字段偏移可能移动,解析必须按建立通信时协商的 revision 对应字段表写,建议在配置里维护偏移而不是硬编码;二是国产控制器"兼容 OpenProtocol"的程度参差不齐,进场前拿控制器实机抓一遍报文,确认支持的 MID 清单和字段长度,别按阿特拉斯文档假设国产设备一致。

四、点位模型:一件产品一张"螺栓地图",缺一颗不放行

防漏拧的数据结构与条码过站(121 篇)同源,但粒度从"工位"细到"螺栓点位"。工艺工程师在产品工艺里定义点位清单:点位号、坐标/图示位置、程序号、目标扭矩、顺序要求。生产时每个 SN 在拧紧工位生成一张点位完成图:

18.61
28.58
38.72
48.49
54.20
68.66
7待拧
8待拧
9待拧
10待拧
11待拧
12待拧

示意:一件产品 12 颗点位,绿色已达标 / 红色第 5 颗扭矩低报 / 灰色待拧。界面按真实螺栓分布布点,工人抬头就知道差哪颗。

关键字段作用
bolt_spec(点位工艺)model、point_no、pset_id、target_torque、tol±、angle_win、seq_group、img_x/img_y型号的螺栓地图,换型随产品型号加载
bolt_result(拧紧结果)sn、point_no、torque、angle、status、detail_status、pset_id、gun_id、operator、ts、tightening_id一颗一行只追加;tightening_id 对应控制器内曲线编号
public enum BoltGate { Ok, UnknownPoint, WrongPset, Duplicate, OutOfWindow, BatchNotDone }

public class TighteningService
{
    public BoltGate Accept(string sn, TighteningResult r)
    {
        var spec = _db.BoltSpecs.FirstOrDefault(s => s.Model == _ctx.Model &&
                                                        s.PointNo == r.PointNo);
        if (spec == null) return BoltGate.UnknownPoint;     // 点位不属于该型号

        // 程序号必须与该点位工艺一致——防止拿错刀或选错程序
        if (r.PsetId != spec.PsetId) return BoltGate.WrongPset;

        // 重复拧:该点位已有OK结果,再来一颗必须走复扭流程,不直接覆盖
        var existed = _db.BoltResults.FirstOrDefault(b => b.Sn == sn &&
                                                           b.PointNo == r.PointNo && b.Ok);
        if (existed != null && !_ctx.HasRepairTicket(sn))
            return BoltGate.Duplicate;

        if (!r.TorqueOk || !r.AngleOk) return BoltGate.OutOfWindow;

        // 条件INSERT/唯一约束 (sn, point_no, 拧紧轮次) 兜底并发重复推送
        _db.BoltResults.Add(Map(sn, r, spec));
        _db.SaveChanges();
        return BoltGate.Ok;
    }

    public bool AllDone(string sn)
    {
        var specs = _db.BoltSpecs.Where(s => s.Model == _ctx.Model).ToList();
        var okPts = _db.BoltResults.Where(b => b.Sn == sn && b.Ok)
                                   .Select(b => b.PointNo).ToHashSet();
        return specs.All(s => okPts.Contains(s.PointNo));   // 缺一颗都不行
    }
}

五、工位流程:程序号跟着 SN 走,使能由 PLC 兜底

1扫 SN 进站加载该型号螺栓地图,界面点亮点位
2下发程序号OpenProtocol 发0018 / IO置选择位+选通脉冲
3PLC 使能工具工件到位+夹具夹紧+程序号回读一致,才给工具24V
4逐颗拧紧每颗结果实时回填点位图,语音/灯提示
5全 OK 放行BatchDone+点位全齐,上位机给PLC放行信号

IO 方式下程序号切换的经典做法:N 个程序号用 3~4 个 PLC 输出点做二进制编码(点位 1~12 映射到各自 Pset),切换时先置位编码、延时一个扫描周期、再给"参数集选择"脉冲,随后必须回读控制器当前程序号(OpenProtocol 下控制器会主动推 MID 0060)比对一致再使能工具。跳过回读这一步,现场最常见的事故就是:换型后程序号没切成功,整班产品用错扭矩。

// IO方式:通过PLC(S7/Modbus点表)下发程序号并回读确认
public async Task<bool> SelectPsetWithVerify(int pset, CancellationToken ct)
{
    for (int bit = 0; bit < 4; bit++)
        _plc.Write($"DB10.DBX2.{bit}", (pset & (1 << bit)) != 0);  // 4位二进制编码

    _plc.Write("DB10.DBX4.0", true);             // 选通脉冲
    await Task.Delay(150, ct);
    _plc.Write("DB10.DBX4.0", false);

    var deadline = DateTime.Now.AddSeconds(3);
    while (DateTime.Now < deadline)
    {
        if ((ushort)_plc.Read("DB11.DBW20") == pset)  // 回读当前Pset
            return true;
        await Task.Delay(100, ct);
    }
    return false;     // 切换失败:禁止使能工具,声光报警提示人工
}

六、NG 与复扭:异常必须留痕,不能"再打一次就算了"

  • 扭矩低报:大概率浮锁/漏垫片/孔位偏。不允许原位直接补打(螺纹已有应力),系统引导拆检后重新拧,原 NG 记录保留、新记录轮次 +1;
  • 扭矩高报:查螺纹损伤、错用程序、零件错料;连续两颗高报自动暂停工位,防止整批螺纹报废;
  • 重复拧:同一点位收到第二次结果直接拦,班组长刷卡开复扭单(写明原因),复扭前后值都进追溯;
  • 滑牙/空打:控制器角度转了扭矩没起来的曲线特征,NG 且锁定工具,必须换新螺丝/镶件后授权复位;
  • 批次未完成不能放行:PLC 放行条件里串入"点位全齐 + BatchDone",物理上挡住漏拧品流到下一站。

七、数据怎么用:追溯、曲线和扭矩 SPC

bolt_result 与 SN 绑定后,自然接上追溯体系(121 篇):反向查某件产品每颗螺丝的扭矩/角度/操作人/刀具编号;正向按刀号查——某把电批扭矩持续正偏,说明扭矩传感器漂移或机械老化,该刀生产过的 SN 范围一键圈出复核。扭矩曲线文件量大(一条几百 KB),数据库只存曲线编号和文件路径(按日期/刀号分目录存工控机本地,定期归档服务器),不要把曲线塞进关系库。

数据攒够之后做扭矩 SPC:同一程序号连续产品的扭矩值分组算均值、标准差、Cpk,控制图上出现连续偏置或趋势时提前调整工具(下一篇 123 专门讲控制图判异规则)。现场经验:扭矩 Cpk 低于 1.33 先别急着怀疑电批,八成是螺栓批次摩擦系数变了或套筒磨损——这正是数据追溯的价值。

时间同步与刀号不能省。多把刀共线时每条结果必须带控制器编号和工位号,否则两把刀的结果会串到同一件产品上;所有时间戳以上位机/服务器为准(见 121 篇),控制器时钟只作辅助。换刀、校扭矩、程序修改这三类事件要单独记设备台账,追溯时才能还原"当时这把刀是什么状态"。

八、上线验收清单

  1. 漏拧:12 颗点位故意少打 1 颗,工位不放行、点位图正确提示缺哪颗;
  2. 错程序:手动把控制器切到错误 Pset 后打钉,WrongPset 拦截并报警;换型切换后回读值与工单一致才使能;
  3. 重复拧:同一颗打两次,第二次被拦,刷班长卡走复扭流程后新旧两条记录都可查;
  4. NG 拦截:模拟扭矩低报,工具锁定/分流正确,原位补打不覆盖 NG 记录;
  5. 断连:拔掉网线连续打钉,控制器本地缓存结果(主流控制器支持),恢复后补传不丢,点位状态最终一致;
  6. 追溯:随机抽 5 件产品,每颗螺丝的扭矩、角度、程序号、操作人、刀号、时间 5 分钟内查全,曲线可调取。

拧紧工位做好之后,"螺丝问题"从产线最大的隐性漏点变成数据最完整的工序之一:程序号跟着产品走、工具使能跟着工艺走、每颗结果跟着 SN 走、异常处理跟着授权走。一颗普通螺丝值不了几分钱,但把它的扭矩数据焊进质量档案,客户端审核时你拿出来的就是一整面墙的底气。