So arbeiten Sie korrekt mit ExtensionObject und Struct in milo opc ua

Nov 20 2020

Ich möchte fragen, wie ich mit Struct richtig arbeiten soll, wenn ich versuche, ein Objekt von einem opc ua-Server zu lesen. Ich habe dieses Beispiel durchgearbeitet und konnte die Daten lesen.

Aber im Moment weiß ich nicht, wie ich sie richtig lesen soll. Stellen wir uns vor, ich lese eine Datenstruktur mit zwei Arrays für x- und y-Werte. Ich habe versucht, so etwas zu tun:

 Float[] x = (Float[])struct.getMember("x").getValue()
 Float[] y = (Float[])struct.getMember("y").getValue()

aber ich erhalte die Ausnahme "'java.lang.Object []' kann nicht in 'java.lang.Float []' umgewandelt werden" Ich kann dies folgendermaßen tun:

float[] x = new float[100];
        int i = 0;
        for(Object o: (Object[])struct.getMember("x").getValue()){
            x[i] = (Float)o;
            i++;
        }

aber ich denke nicht, dass das richtig sein könnte.

Auf jeden Fall möchte ich etwas Ähnliches erreichen, wie das Lesen einer JSON-Datei mit Jackson. Um eine Klasse mit dem gleichen Namen wie die "Mitglieder zu haben und mit geeigneten Typen zu haben und etwas zu tun wie:

OpcuaReader reader = ...
MyClass myClass = reader.read(struct, MyClass.class)

Ich könnte völlig falsch liegen, könnte mir jemand vorschlagen, wie ich ein solches Problem lösen soll?

Antworten

1 IstvánBékési Nov 23 2020 at 08:19

Erstens können Sie eine Reihe solcher Objekte nicht umwandeln. Stattdessen können Sie die Stream-API verwenden, um Floats wie folgt zu erstellen:

Object[] objectArray = { 1.0f, 2.0f, 3, 4, 5 };
Float floatArray[] = Arrays.stream(objectArray)
  .map(Object::toString)
  .map(Float::valueOf)
  .toArray(Float[]::new);

Über den Milo-Client gibt es ein großartiges Beispiel für das Lesen benutzerdefinierter Datentypen in ReadWriteCustomDataTypeNodeExample .

Sie können einen eigenen Typ erstellen, der CustomStructTypeder Dekodierungsmethode ähnelt, und diese selbst überschreiben. Der Decoder verfügt außerdem über eine integrierte readFloatArrayMethode:

@Override
public CustomStructType decode(
    SerializationContext context,
    UaDecoder decoder) throws UaSerializationException {

    String foo = decoder.readString("Foo");
    UInteger bar = decoder.readUInt32("Bar");
    boolean baz = decoder.readBoolean("Baz");

    Float[] floatArray = decoder.readFloatArray("floatArray");

    return new CustomStructType(foo, bar, baz);
}
JakubZnamenáček Nov 26 2020 at 16:15

Vielen Dank an istibekesi , wir schaffen es, dass es funktioniert. Für jemanden, der hier das gleiche Problem hätte, müssen Sie Folgendes tun:

1) Suchen Sie die TYPE_ID

  • Sie müssen den NamespaceIndex und den Bezeichner des Datentyps der Struktur (des Objekts) finden, die Sie über OPC UA lesen möchten, beispielsweise mit UaExpert
  • Wenn Sie nicht sicher sind, welcher Datentyp es ist, finden Sie einfach eine Variable, die diese Struktur darstellt, und dort sehen Sie die Datentyp-Informationen auf der rechten Seite des Bildschirms, wenn Sie darauf klicken.

2) Suchen Sie die BINARY_ENCODING_ID

  • Um diesen zu finden, müssen Sie mit UaExpert nach dem Datentyp selbst suchen. Einige davon befinden sich unter Typen / Datentypen ...
  • Wenn Sie es finden, klicken Sie darauf, um weitere Informationen zu erhalten
  • Dann wird im rechten unteren Teil Ihres Bildschirms "HasEncoding | Default Binary" angezeigt und Sie doppelklicken darauf
  • Auf diese Weise erhalten Sie den NamespaceIndex und den Bezeichner für BINARY_ENCODING_ID

3) Folgen Sie diesem Beispiel

  • Um alle Teile von milo zu haben, die Sie benötigen, müssen Sie sdk-client , dictionary-reader , bsd-parser in Ihre Abhängigkeiten aufnehmen
  • Erstellen Sie eine ähnliche Klasse:
public class OpcuaCurve implements UaStructure {

    public static final ExpandedNodeId TYPE_ID = ExpandedNodeId.parse("ns=3;s=DT_\"PrServo_typeRuntimeDriveDiagnosticsProcessValuesTrends\".\"hmiTrend\"");

    public static final ExpandedNodeId BINARY_ENCODING_ID = ExpandedNodeId.parse("ns=3;s=TE_\"PrServo_typeRuntimeDriveDiagnosticsProcessValuesTrends\".\"hmiTrend\"");

    private final Float[] torque;
    private final Float[] speed;

    public OpcuaCurve() {
        this(null, null);
    }

    public OpcuaCurve(Float[] torque, Float[] speed) {
        this.torque = torque;
        this.speed = speed;
    }

    public Float[] getSpeed() {
        return speed;
    }

    public Float[] getTorque() {
        return torque;
    }

    @Override
    public ExpandedNodeId getTypeId() {
        return TYPE_ID;
    }

    @Override
    public ExpandedNodeId getBinaryEncodingId() {
        return BINARY_ENCODING_ID;
    }

    @Override
    public ExpandedNodeId getXmlEncodingId() {
        // XML encoding not supported
        return ExpandedNodeId.NULL_VALUE;
    }







    public static class Codec extends GenericDataTypeCodec<OpcuaCurve> {
        @Override
        public Class<OpcuaCurve> getType() {
            return OpcuaCurve.class;
        }

        @Override
        public OpcuaCurve decode(
            SerializationContext context,
            UaDecoder decoder) throws UaSerializationException {

            Float[] torqueArray = decoder.readFloatArray("motorTorque");
            Float[] speedArray = decoder.readFloatArray("motorSpeed");

            return new OpcuaCurve(torqueArray,speedArray);
        }

        @Override
        public void encode(
                SerializationContext context,
                UaEncoder encoder, OpcuaCurve value) throws UaSerializationException {

            encoder.writeFloatArray("motorTorque", value.torque);
            encoder.writeFloatArray("motorTorque", value.speed);
        }
    }

}
  • und beim Registrieren des Decoders beim Client wie folgt:
private void registerCustomCodec(OpcUaClient client) {
        NodeId binaryEncodingId = OpcuaCurve.BINARY_ENCODING_ID
                .local(client.getNamespaceTable())
                .orElseThrow(() -> new IllegalStateException("namespace not found"));

        // Register codec with the client DataTypeManager instance
        client.getDataTypeManager().registerCodec(
                binaryEncodingId,
                new OpcuaCurve.Codec().asBinaryCodec()
        );
    }