APIs, concepts, guides, and more
PDO vs. SDO

Understand the difference between real-time data exchange with PDOs and periodic service channel messages with SDOs in EtherCAT, and learn how to read, write, and configure these using RapidSetup and the RapidCode API.

In EtherCAT, values are sent and received from most drives using CANopen PDO’s and SDO’s. In most applications, RapidCode API users need not be aware of these low-level features.

  • PDO (Process Data Object) → Real-time data sent to/from the MotionController to each drive/node for every sample period.
  • SDO (Service Data Object) → Service Channel messages which are not exchanged every cycle.

🔹 What are PDOs?

PDOs or Process Data Objects are the values exchanged cyclically with every real-time sample of the MotionController (1kHz by default). For servo drives, these are values such as control/status information and position demand/feedback.

Multi-Threading Note
→ Writing to the same PDO values is not Multi-Threading safe.
→ Writing to different PDO values is Multi-Threading safe.

Reading & Writing

  • RapidCode ⚙️

    Reading Inputs

    public void NetworkInputs()
    {
    int inputCount = controller.NetworkInputCountGet();
    for (int i = 0; i < inputCount; i++)
    {
    int size = controller.NetworkInputBitSizeGet(i);
    int offset = controller.NetworkInputBitOffsetGet(i);
    string name = controller.NetworkInputNameGet(i);
    UInt64 value = controller.NetworkInputValueGet(i);
    }
    }

    Reading & Writing to Outputs

    public void NetworkOutputs()
    {
    int outputCount = controller.NetworkOutputCountGet();
    for (int i = 0; i < outputCount; i++)
    {
    int size = controller.NetworkOutputBitSizeGet(i);
    int offset = controller.NetworkOutputBitOffsetGet(i);
    string name = controller.NetworkOutputNameGet(i);
    UInt64 value = controller.NetworkOutputValueGet(i);
    //If you intend to write outputs, you only need to do this once.
    controller.NetworkOutputOverrideSet(i, true);
    //Anytime you want to write a specific output value.
    controller.NetworkOutputOverrideValueSet(i, value); //←Write to a PDO output.
    }
    }
    Note
    Be sure you know what you are doing if you choose to Override an Output. Any automated process which was writing to it, will no longer have control and will not be aware that someone else is in charge.

  • RapidSetup 🖥️

    Open the RapidSetup tool then go to Tools > Network Data

    Here you can see which PDO’s are being exchanged between our controller and your device/node(s).

    Network Data Page - RapidSetup v8.1.5

Data Injection

You can inject exchanged information (changing defaults) by creating the CustomNodeInfo.xml.

Let's say we want to read/write from the latch status, control, and positions SDO’s because communicating directly with the SDO takes too much time.

Follow the Example below for a solution.

Using CustomNodeInfo.xml File

In the default NodeInfo.xml file Yaskawa (for example) by default has the following PDO’s configuration:

<PDOs>
<PDOAssignment Index="0x1601" IsOutput="True" Include="False" />
<PDOAssignment Index="0x1a01" IsOutput="False" Include="False" />
<PDOAssignment Index="0x1600" IsOutput="True" Include="True" RemoveContent="0x6060 0x6072" />
<PDOAssignment Index="0x1a00" IsOutput="False" Include="True" />
</PDOs>

Take a look at the Yaskawa-SGD7S.xml ESI file, located in the ESI folder inside the RMP folder:

<Object>
<Index>#x60B8</Index>
<Name>Touch probe function</Name>
<Type>UINT</Type>
<BitSize>16</BitSize>
<Flags>
<Access>rw</Access>
<PdoMapping>RT</PdoMapping>
</Flags>
</Object>
<Object>
<Index>#x60B9</Index>
<Name>Touch probe status</Name>
<Type>UINT</Type>
<BitSize>16</BitSize>
<Flags>
<Access>ro</Access>
<PdoMapping>T</PdoMapping>
</Flags>
</Object>
<Object>
<Index>#x60BA</Index>
<Name>Touch probe 1 position value</Name>
<Type>DINT</Type>
<BitSize>32</BitSize>
<Flags>
<Access>ro</Access>
<PdoMapping>T</PdoMapping>
</Flags>
</Object>
<Object>
<Index>#x60BC</Index>
<Name>Touch probe 2 position value</Name>
<Type>DINT</Type>
<BitSize>32</BitSize>
<Flags>
<Access>ro</Access>
<PdoMapping>T</PdoMapping>
</Flags>
</Object>

You can add multiple AddEntry by copying the relevant Vendor from NodeInfo.xml and pasting it to CustomNodeInfo.xml and making the following changes:

<PDOs>
<PDOAssignment Index="0x1601" IsOutput="True" Include="False" />
<PDOAssignment Index="0x1a01" IsOutput="False" Include="False" />
<PDOAssignment Index="0x1600" IsOutput="True" Include="True" RemoveContent="0x6060" />
<PDOAssignment Index="0x1a00" IsOutput="False" Include="True" />
<AddEntry Name="Touch probe 1 position value" Index="0x60BA" SubIndex="0" BitLen="32" DataType="DINT" />
<AddEntry Name="Touch probe status" Index="0x60B9" SubIndex="0" BitLen="16" DataType="UINT" />
<AddEntry Name="Touch probe 2 position value" Index="0x60BC" SubIndex="0" BitLen="32" DataType="DINT" />
</PDOAssignment>
</PDOs>

This works well for Inputs:

<Access>ro</Access>

like Touch probe values and status. But it does not work currently for Outputs:

<Access>rw</Access>

such as the Touch probe function (0x60B8). Right now if you add an output in, RMP will write 0 into it every cycle. Unless you Override the sent value (see next section).

Output Override

🔹 What are SDOs?

SDOs or Service Data Object are messages in a confirmed service with a kind of handshake. They are used for the access to entries of the object dictionary. Especially the configuration for the requested behavior of the drive adapted to the various possible applications is done by these objects.

Note
→ SDO’s are not exchanged during every cycle, they are done periodically.
→ Not as fast as PDO’s since they must wait for network response

Reading & Writing

📜 Sample Code

  • C#

    // get Input values
    int inputCount = controller.NetworkInputCountGet(); // get number of Network Inputs (PDOs)
    Console.WriteLine($"Network Input Count: {inputCount}");
    for (int i = 0; i < inputCount; i++)
    {
    int size = controller.NetworkInputBitSizeGet(i); // read Input BitSize
    int offset = controller.NetworkInputBitOffsetGet(i); // read Input BitOffset
    string name = controller.NetworkInputNameGet(i); // read Input Name
    UInt64 value = controller.NetworkInputValueGet(i); // read Input Value
    Console.WriteLine($"Input {i}: {name}, Size: {size}, Offset: {offset}, Value: {value}");
    }
    // get Output values
    int outputCount = controller.NetworkOutputCountGet(); // get number of Network Outputs (SDOs)
    Console.WriteLine($"Network Output Count: {outputCount}");
    for (int i = 0; i < outputCount; i++)
    {
    int size = controller.NetworkOutputBitSizeGet(i); // read Output BitSize
    int offset = controller.NetworkOutputBitOffsetGet(i); // read Output BitOffset
    string name = controller.NetworkOutputNameGet(i); // read Output Name
    UInt64 value = controller.NetworkOutputSentValueGet(i); // read Output Value
    Console.WriteLine($"Output {i}: {name}, Size: {size}, Offset: {offset}, Value: {value}");
    controller.NetworkOutputOverrideValueSet(i, value);
    }