c# OPC 客户端:OPCGroup.SyncWrite 有时会失败

问题描述

为了连接到 Rockwell Rslinx,我制作了一个 opc 客户端。我只使用了 OPCgroup.SyncRead 和 SyncWrite。 一切正常,我从 Rockwell plc 写入和读取标签。 为了测试 SyncWrite,我使用了一个正弦波,我在 plc 的趋势页面中正确地看到了它。 此外,当我按下表单上的一个按钮时,我会设置一个值,直到我一直按下按钮,当我松开按钮时会返回零(假设是一个脉冲)。 该值写入 PLC,我可以在趋势中检查它。然后我以表格形式从 PLC 读回它。 为此,我用正弦波的值对 array[0] 充电,用脉冲的值对 array[1] 充电。然后将数组传递给 SyncWrite。 所以,正如我所说,一切正常。 但现在我不得不添加一个功能。这是一个二阶系统(T(s) 或二阶滤波器)。 我当然使用相同的数组,现在数组 [0] 是过滤器的结果,数组 [1] 又是脉冲。 脉冲从 PLC 读回,现在是扰乱系统的力。 为了从正弦波计算切换到滤波,我使用了一个按钮,可以交替启用滤波或正弦波。 在这里我很疯狂,因为当我切换到过滤器并按下生成要从 plc 读回的脉冲的按钮时,主要是脉冲没有到达 PLC。 但最奇怪的是,在 array[1] 中,我看到了脉冲的值。当我在下面的行中设置中断点时,我在调试中看到了这一点 同步写入

  public static void Write_synchr(RSIOPC r)
    {
      try
        {
          DataToSend.SetValue(r.array_to_send,1);
          r.RSLinxOPCgroup_w.SyncWrite(1,ref r.SyncServerHandles_w,ref DataToSend,out SyncErrors2);
        }
      catch (Exception e)
        {
          MessageBox.Show(e.ToString(),"Error:  ",MessageBoxButtons.OK,MessageBoxIcon.Error);
        }

    }

更奇怪的是,有时我看到它工作,我不知道如何,但并非总是如此。所以我试图纠正,所以我来到了这一点。 当我看到它有时工作时,sw 激活停用滤波器或正弦波的策略是不同的,但在我看来是错误的。事实上,它并不总是有效。 在它工作时,我还可以看到并测试滤波器响应脉冲的行为,这很好。

解决方法

我做了很多测试,发现了这种奇怪的行为。 如果我使用以下

public float test_second_order_filter()
    {
        force[0] = ... the result of the SyncRead to read the value of the pulse ...
        filter[0] = (float) (-(filter[2] * param_filter[2] / param_filter[0]) - (filter[1] * param_filter[1] / param_filter[0]) +
                     +(force[2] * param_force[2] / param_filter[0]) + (force[1] * param_force[1] / param_filter[0]) +
                        +(force[0] * param_force[0] / param_filter[0]));
        filter[2] = filter[1];
        filter[1] = filter[0];
        force[2] = force[1];
        force[1] = force[0];
        return filter[0];
    }

这正是我必须做的,但行为是我上一篇文章中描述的

然后我尝试了一个简化版本:

public float test_second_order_filter()
    {
        force[0] = ... the result of the SyncRead to read the value of the pulse ...
        filter[0] = (float) (force[0] + filter[2]);
        filter[2] = filter[1];
        filter[1] = filter[0];
        force[2] = force[1];
        force[1] = force[0];
        return filter[0];
    }

(这里的公式没有意义)又没办法

然后我尝试了这个:

public float test_second_order_filter()
    {
        force[0] = ... the result of the SyncRead to read the value of the pulse ...
        filter[0] = (float) (force[0] + 1 + filter[2]);
        filter[2] = filter[1];
        filter[1] = filter[0];
        force[2] = force[1];
        force[1] = force[0];
        return filter[0];
    }

(这里的公式没有意义)发生了一些事情,当我按下按钮时,有时脉冲到达 PLC,我看到 PLC 趋势在移动。来自 ....try ... catch 错误多次导致 SyncWrite 中的访问冲突,但代码不会停止并继续执行某些操作。

然后我尝试了这个:

public float test_second_order_filter()
    {
        force[0] = ... the result of the SyncRead to read the value of the pulse ...
        filter[0] = (float) (force[0] + 0.005 + filter[2]);
        filter[2] = filter[1];
        filter[1] = filter[0];
        force[2] = force[1];
        force[1] = force[0];
        return filter[0];
    }

(这里的公式没有意义)现在系统正在工作(...好的,公式没有意义但它有效)。如果我按下按钮,我会看到 PLC 中的脉冲,该脉冲从表格中的 PLC 本身读回,因此我看到它反映在 force[0] 中。这是我需要做的,但使用第一个代码示例公式。

所以在我看来,这与浮动管理有关。我不能使用 double 类型,因为 SyncRead 和 SyncWrite 都返回错误。

参考我的第一篇文章

public static void Write_synchr(RSIOPC r)
{
  try
    {
      DataToSend.SetValue(r.array_to_send,1);
      r.RSLinxOPCgroup_w.SyncWrite(1,ref r.SyncServerHandles_w,ref DataToSend,out SyncErrors2);
    }
  catch (Exception e)
    {
      MessageBox.Show(e.ToString(),"Error:  ",MessageBoxButtons.OK,MessageBoxIcon.Error);
    }

}

在循环中,我将 r.array_to_send[0] 的值设置为 filter[0] 的值,将 r.array_to_send[1] 的值设置为使用表单中的按钮生成的脉冲值。

我想记住,使用以下公式我完全没有问题

r.array_to_send[0] = (float)(2 * Math.Cos((2 * (1.0 / Time_period[0]) * Math.PI) * t));

问候

,

我想已经找到原因了。最有可能是浮点管理(有很多关于使用浮点数发生灾难性错误的文献)。可能另外在 OPCAuto.dll Rockwell 包装器 (RsiOpcAuto.dll) 中还有一些带有浮点数的东西。我尝试将滤波器计算的结果除以 10(在 PLC 中,我然后乘以 10),然后除以 100,然后是 1000,最后是 1000'000'000,然后事情变得更好了。我告诉我,在执行 OPCGroup.SyncWrite 时,我有时会收到有关 Rockwell 包装器中某些访问冲突的错误。当我开始除以 10 的幂时,我收到错误的频率降低了。可能解决方案是截断任何计算的结果,特别是在减法时。我读到减法是指近似导致那些灾难性错误。