RECORD access via PC-SDK

Hi all,

I have an array of RECORD like below. How can I access it with struct in PC-SDK?

RECORD rec
num myNum;
pos myPos;
ENDRECORD

PERS rec myArray{2}:=[ [ 2, [ 1, 2, 3 ] ], [ 3,[ 4, 5, 6 ] ] ];

Thanks for the help.

Hi,

Hereby a sample program. If you have any questions about it, just let me know :smile:

using System;
using ABB.Robotics.Controllers;
using ABB.Robotics.Controllers.Discovery;
using ABB.Robotics.Controllers.RapidDomain;
using System.Linq;
using System.Windows.Media.Media3D;

namespace PCSDKTest2
{
    class Program
    {
        public struct Rec
        {
            public double myNum { get; set; }
            public Vector3D myPos { get; set; }
        }

        private static Pos VectorToPos(Vector3D v)
        {
            return new Pos() { X = (float)v.X, Y = (float)v.Y, Z = (float)v.Z };
        }

        private static Vector3D PosToVector(Pos p)
        {
            return new Vector3D(p.X, p.Y, p.Z);
        }

        private static RapidData[] LoadData(Controller c, Task t, string rapidType)
        {
            // variables
            RapidSymbolSearchProperties searchProps;
            RapidSymbol[] rapidSymbols;
            RapidData[] rapidDatas = null;

            // check arguments
            if (c != null && t != null && !string.IsNullOrEmpty(rapidType))
            {
                // define search properties
                searchProps = RapidSymbolSearchProperties.CreateDefaultForData();
                searchProps.Recursive = true;
                searchProps.Types = SymbolTypes.Persistent;

                // search for results
                rapidSymbols = t.SearchRapidSymbol(searchProps);

                // convert results to rapid-data
                rapidDatas = rapidSymbols.Select(rs => new RapidData(c, rs)).Where(rs => rs.RapidType == rapidType).ToArray();
            }

            // return
            return rapidDatas;
        }

        private static Rec[] ConvertToRec(RapidData rapid)
        {
            // variables
            Num num;
            Pos pos;
            ArrayData value;
            UserDefined element;
            Rec[] rec;

            // check arguments
            if (rapid?.Value != null && rapid.IsArray)
            {
                // convert to ArrayData
                value = (ArrayData)rapid.Value;

                // define resulting array
                rec = new Rec[value.Length];

                for (int i = 0; i<value.Length; i++)
                {
                    // get the struct-data
                    element = (UserDefined)rapid.ReadItem(i + value.BaseIndex);

                    // get the pos and num
                    num = (Num)element.Components[0];
                    pos = (Pos)element.Components[1];

                    // create Rec
                    rec[i] = new Rec()
                    {
                        myNum = num.Value,
                        myPos = PosToVector(pos)
                    };
                }

                // return 
                return rec;
            }
            else
            {
                throw new ArgumentException("The RapidData should be defined as ArrayData");
            }
        }

        private static void Save(Controller c, RapidData rapid, Rec[] rec)
        {
            // variables
            ArrayData value;
            UserDefined element;

            if (c != null && rapid?.Value != null && rapid.IsArray)
            {
                try
                {
                    // request mastership, needed to write values
                    using (Mastership ms = Mastership.Request(c.Rapid))
                    {
                        // convert to ArrayData
                        value = (ArrayData)rapid.Value;

                        // write items
                        for (int i = 0; i < value.Length; i++)
                        {
                            // get the struct-data
                            element = (UserDefined)rapid.ReadItem(i + value.BaseIndex);

                            // update 
                            element.Components[0] = new Num(rec[i].myNum);
                            element.Components[1] = VectorToPos(rec[i].myPos);

                            // save
                            rapid.WriteItem(element, i + value.BaseIndex);
                        }
                    }
                }
                catch(Exception ex) { }
            }
        }

        static void Main(string[] args)
        {
            // variables
            NetworkScanner ns;
            Controller c;
            Task t;
            Rec[] rec;
            RapidData[] rapidDatas;

            try
            {
                // scan network
                ns = new NetworkScanner();
                ns.Scan();

                // get first found controller
                if (ns.Controllers.Count > 0)
                {
                    // create the controller
                    c = new Controller(ns.Controllers[0]);
                    if (c != null)
                    {
                        // log on 
                        c.Logon(UserInfo.DefaultUser);

                        t = c.Rapid.GetTask("T_ROB1");
                        if (t != null)
                        {
                            // load data
                            rapidDatas = LoadData(c, t, "rec");
                            if (rapidDatas.Length > 0)
                            {
                                // conver to Rec
                                rec = ConvertToRec(rapidDatas[0]);
                                if (rec.Length > 0)
                                {
                                    // increment values
                                    rec[0].myNum += 1;
                                    rec[0].myPos += new Vector3D(2, 3, 4);
                                }

                                // save 
                                Save(c, rapidDatas[0], rec);
                            }
                        }

                        //log off
                        c.Logoff();

                        // dispose controller
                        c.Dispose();
                    }
                }
            }
            catch (Exception e) { }
        }
    }
}

Thanks, John_Verheij!! I will give this a go and let you know how it goes.

Thank you very much for this John_Verheij. Works like magic!

I also took it further by making the structure implement IRapidData like below. This allows the variable to have more or less the same function as the other RapidDomain structures.
In this sample, rec RECORD is defined in RS as follows:

RECORD rec
num num1;
robtarget tgt;
ENDRECORD

public struct Rec : IRapidData
{
    // Structure fields
    private Num num;
    private RobTarget tgt;
    private RapidData refRapidData;
 
    // Structure properties
    public Num NumVal
    {
        get { return num; }
        set { num = value; }
    }
 
    public RobTarget TgtVal
    {
        get { return tgt; }
        set { tgt = value; }
    }
 
    public static Rec Empty
    {
        get;
    }
 
    public Rec(RapidData input)
    {
        UserDefined ud = (UserDefined)input.Value;
 
        // Initialise struct fields from the RapidData:
        // ~ refRapidData takes the REFERENCE of the RapidData. This is useful in SaveToRapidData() method.
        // ~ num & tgt takes the VALUE of the RapidData components. This is useful in making internal temporary 
        //   changes before saving it (back) to the RapidData by SaveToRapidData() method.
        this.num = (Num)ud.Components[0];
        this.tgt = (RobTarget)ud.Components[1];
        refRapidData = input;
    }
 
    public override string ToString()
    {
        return "[" + NumVal + "," + TgtVal + "]";
    }
 
    public void SaveToRapidData()
    {
        // c is the controller defined globally. Required to request mastership.
        using (Mastership ms = Mastership.Request(c.Rapid))
        {
            refRapidData.StringValue = this.ToString();
        }
    }
 
    public void Fill(string value)
    {
        char[] delimiterChars = { ' ', ',', '[', ']' }; // Get rid of these chars from the value input
        string[] tokens = value.Split(delimiterChars, StringSplitOptions.RemoveEmptyEntries);
 
        // Assign struct's fields: NumVal
        NumVal = new Num(Convert.ToDouble(tokens[0]));
 
        // Assign struct's fields: TgtVal
        RobTarget newTgt = new RobTarget();
        newTgt.Trans.X = Convert.ToSingle(tokens[1]);
        newTgt.Trans.Y = Convert.ToSingle(tokens[2]);
        newTgt.Trans.Z = Convert.ToSingle(tokens[3]);
        newTgt.Rot.Q1 = Convert.ToSingle(tokens[4]);
        newTgt.Rot.Q2 = Convert.ToSingle(tokens[5]);
        newTgt.Rot.Q3 = Convert.ToSingle(tokens[6]);
        newTgt.Rot.Q4 = Convert.ToSingle(tokens[7]);
        newTgt.Robconf.Cf1 = Convert.ToInt32(tokens[7]);
        newTgt.Robconf.Cf4 = Convert.ToInt32(tokens[8]);
        newTgt.Robconf.Cf6 = Convert.ToInt32(tokens[9]);
        newTgt.Robconf.Cfx = Convert.ToInt32(tokens[10]);
        newTgt.Extax.Eax_a = Convert.ToSingle(tokens[11]);
        newTgt.Extax.Eax_b = Convert.ToSingle(tokens[12]);
        newTgt.Extax.Eax_c = Convert.ToSingle(tokens[13]);
        newTgt.Extax.Eax_d = Convert.ToSingle(tokens[14]);
        newTgt.Extax.Eax_e = Convert.ToSingle(tokens[15]);
        newTgt.Extax.Eax_f = Convert.ToSingle(tokens[16]);
        TgtVal = newTgt;
    }
 
    public void Fill(DataNode root)
    {
        throw new NotImplementedException();
    }
 
    public void FillFromString(string newValue)
    {
        Fill(newValue);
    }
 
    public DataNode ToStructure()
    {
        throw new NotImplementedException();
    }
}