Service Data Object (SDO)

The SDO protocol is used for setting and for reading values from the object dictionary of a remote device. The device whose object dictionary is accessed is the SDO server and the device accessing the remote device is the SDO client. The communication is always initiated by the SDO client. In CANopen terminology, communication is viewed from the SDO server, so that a read from an object dictionary results in an SDO upload and a write to a dictionary entry is an SDO download.

Because the object dictionary values can be larger than the eight bytes limit of a CAN frame, the SDO protocol implements segmentation and desegmentation of longer messages. Actually, there are two of these protocols: SDO download/upload and SDO Block download/upload. The SDO block transfer is a newer addition to standard, which allows large amounts of data to be transferred with slightly less protocol overhead.

The COB-IDs of the respective SDO transfer messages from client to server and server to client can be set in the object dictionary. Up to 128 SDO servers can be set up in the object dictionary at addresses 0x1200 - 0x127F. Similarly, the SDO client connections of the device can be configured with variables at 0x1280 - 0x12FF. However the pre-defined connection set defines an SDO channel which can be used even just after bootup (in the Pre-operational state) to configure the device. The COB-IDs of this channel are 0x600 + node ID for receiving and 0x580 + node ID for transmitting.

Examples

SDO objects can be accessed using the .sdo member which works like a Python dictionary. Indexes and subindexes can be identified by either name or number. The code below only creates objects, no messages are sent or received yet:

# Complex records
command_all = node.sdo['ApplicationCommands']['CommandAll']
actual_speed = node.sdo['ApplicationStatus']['ActualSpeed']
control_mode = node.sdo['ApplicationSetupParameters']['RequestedControlMode']

# Simple variables
device_type = node.sdo[0x1000]

# Arrays
error_log = node.sdo[0x1003]

To actually read or write the variables, use the .raw, .phys, .desc, or .bits attributes:

print("The device type is 0x%X" % device_type.raw)

# Using value descriptions instead of integers (if supported by OD)
control_mode.desc = 'Speed Mode'

# Set individual bit
command_all.bits[3] = 1

# Read and write physical values scaled by a factor (if supported by OD)
print("The actual speed is %f rpm" % actual_speed.phys)

# Iterate over arrays or records
for error in error_log.values():
    print("Error 0x%X was found in the log" % error.raw)

It is also possible to read and write to variables that are not in the Object Dictionary, but only using raw bytes:

device_type_data = node.sdo.upload(0x1000, 0)
node.sdo.download(0x1017, 0, b'\x00\x00')

Variables can be opened as readable or writable file objects which can be useful when dealing with large amounts of data:

# Open the Store EDS variable as a file like object
with node.sdo[0x1021].open('r', encoding='ascii') as infile,
        open('out.eds', 'w', encoding='ascii') as outfile:

   # Iteratively read lines from node and write to file
   outfile.writelines(infile)

Most APIs accepting file objects should also be able to accept this.

Block transfer can be used to effectively transfer large amounts of data if the server supports it. This is done through the file object interface:

FIRMWARE_PATH = '/path/to/firmware.bin'
FILESIZE = os.path.getsize(FIRMWARE_PATH)

with open(FIRMWARE_PATH, 'rb') as infile,
        node.sdo['Firmware'].open('wb', size=FILESIZE, block_transfer=True) as outfile:

    # Iteratively transfer data without having to read all into memory
    while True:
        data = infile.read(1024)
        if not data:
            break
        outfile.write(data)

Warning

Block transfer is still in experimental stage!

API

class canopen.sdo.SdoClient(rx_cobid, tx_cobid, od)[source]

Handles communication with an SDO server.

Parameters:
  • rx_cobid (int) – COB-ID that the server receives on (usually 0x600 + node ID)

  • tx_cobid (int) – COB-ID that the server responds with (usually 0x580 + node ID)

  • od (canopen.ObjectDictionary) – Object Dictionary to use for communication

od

The canopen.ObjectDictionary associated with this object.

c[index]

Return the SDO object for the specified index (as int) or name (as string).

iter(c)

Return an iterator over the indexes from the object dictionary.

index in c

Return True if the index (as int) or name (as string) exists in the object dictionary.

len(c)

Return the number of indexes in the object dictionary.

values()

Return a list of objects (records, arrays and variables).

MAX_RETRIES = 1

Max number of request retries before raising error

PAUSE_BEFORE_SEND = 0.0

Seconds to wait before sending a request, for rate limiting

RESPONSE_TIMEOUT = 0.3

Max time in seconds to wait for response from server

abort(abort_code=134217728)[source]

Abort current transfer.

download(index, subindex, data, force_segment=False)[source]

May be called to make a write operation without an Object Dictionary.

Parameters:
  • index (int) – Index of object to write.

  • subindex (int) – Sub-index of object to write.

  • data (bytes) – Data to be written.

  • force_segment (bool) – Force use of segmented transfer regardless of data size.

Raises:
Return type:

None

open(index, subindex=0, mode='rb', encoding='ascii', buffering=1024, size=None, block_transfer=False, force_segment=False, request_crc_support=True)[source]

Open the data stream as a file like object.

Parameters:
  • index (int) – Index of object to open.

  • subindex (int) – Sub-index of object to open.

  • mode (str) –

    Character

    Meaning

    ’r’

    open for reading (default)

    ’w’

    open for writing

    ’b’

    binary mode (default)

    ’t’

    text mode

  • encoding (str) – The str name of the encoding used to decode or encode the file. This will only be used in text mode.

  • buffering (int) – An optional integer used to set the buffering policy. Pass 0 to switch buffering off (only allowed in binary mode), 1 to select line buffering (only usable in text mode), and an integer > 1 to indicate the size in bytes of a fixed-size chunk buffer.

  • size (int) – Size of data to that will be transmitted.

  • block_transfer (bool) – If block transfer should be used.

  • force_segment (bool) – Force use of segmented download regardless of data size.

  • request_crc_support (bool) – If crc calculation should be requested when using block transfer

Returns:

A file like object.

upload(index, subindex)[source]

May be called to make a read operation without an Object Dictionary.

Parameters:
  • index (int) – Index of object to read.

  • subindex (int) – Sub-index of object to read.

Return type:

bytes

Returns:

A data object.

Raises:
class canopen.sdo.SdoServer(rx_cobid, tx_cobid, node)[source]

Creates an SDO server.

Parameters:
  • rx_cobid (int) – COB-ID that the server receives on (usually 0x600 + node ID)

  • tx_cobid (int) – COB-ID that the server responds with (usually 0x580 + node ID)

  • od (canopen.LocalNode) – Node object owning the server

od

The canopen.ObjectDictionary associated with this object.

c[index]

Return the SDO object for the specified index (as int) or name (as string).

iter(c)

Return an iterator over the indexes from the object dictionary.

index in c

Return True if the index (as int) or name (as string) exists in the object dictionary.

len(c)

Return the number of indexes in the object dictionary.

values()

Return a list of objects (records, arrays and variables).

abort(abort_code=134217728)[source]

Abort current transfer.

download(index, subindex, data, force_segment=False)[source]

May be called to make a write operation without an Object Dictionary.

Parameters:
  • index (int) – Index of object to write.

  • subindex (int) – Sub-index of object to write.

  • data (bytes) – Data to be written.

Raises:

canopen.SdoAbortedError – When node responds with an error.

upload(index, subindex)[source]

May be called to make a read operation without an Object Dictionary.

Parameters:
  • index (int) – Index of object to read.

  • subindex (int) – Sub-index of object to read.

Return type:

bytes

Returns:

A data object.

Raises:

canopen.SdoAbortedError – When node responds with an error.

class canopen.sdo.SdoVariable(sdo_node, od)[source]

Access object dictionary variable values using SDO protocol.

od

The canopen.objectdictionary.ODVariable associated with this object.

property bits: Bits

Access bits using integers, slices, or bit descriptions.

property data: bytes

Byte representation of the object as bytes.

property desc: str

Converts to and from a description of the value as a string.

index

Holds a local, overridable copy of the Object Index

name

Description of this variable from Object Dictionary, overridable

open(mode='rb', encoding='ascii', buffering=1024, size=None, block_transfer=False, request_crc_support=True)[source]

Open the data stream as a file like object.

Parameters:
  • mode (str) –

    Character

    Meaning

    ’r’

    open for reading (default)

    ’w’

    open for writing

    ’b’

    binary mode (default)

    ’t’

    text mode

  • encoding (str) – The str name of the encoding used to decode or encode the file. This will only be used in text mode.

  • buffering (int) – An optional integer used to set the buffering policy. Pass 0 to switch buffering off (only allowed in binary mode), 1 to select line buffering (only usable in text mode), and an integer > 1 to indicate the size in bytes of a fixed-size chunk buffer.

  • size (int) – Size of data to that will be transmitted.

  • block_transfer (bool) – If block transfer should be used.

  • request_crc_support (bool) – If crc calculation should be requested when using block transfer

Returns:

A file like object.

property phys: int | bool | float | str | bytes

Physical value scaled with some factor (defaults to 1).

On object dictionaries that support specifying a factor, this can be either a float or an int. Non integers will be passed as is.

property raw: int | bool | float | str | bytes

Raw representation of the object.

This table lists the translations between object dictionary data types and Python native data types.

Data type

Python type

BOOLEAN

bool

UNSIGNEDxx

int

INTEGERxx

int

REALxx

float

VISIBLE_STRING

str / unicode (Python 2)

UNICODE_STRING

str / unicode (Python 2)

OCTET_STRING

bytes

DOMAIN

bytes

Data types that this library does not handle yet must be read and written as bytes.

read(fmt='raw')

Alternative way of reading using a function instead of attributes.

May be useful for asynchronous reading.

Parameters:

fmt (str) –

How to return the value
  • ’raw’

  • ’phys’

  • ’desc’

Return type:

Union[int, bool, float, str, bytes]

Returns:

The value of the variable.

subindex

Holds a local, overridable copy of the Object Subindex

write(value, fmt='raw')

Alternative way of writing using a function instead of attributes.

May be useful for asynchronous writing.

Parameters:

fmt (str) –

How to write the value
  • ’raw’

  • ’phys’

  • ’desc’

Return type:

None

class canopen.sdo.SdoRecord(sdo_node, od)[source]
od

The canopen.objectdictionary.ODRecord associated with this object.

record[subindex]

Return the canopen.sdo.SdoVariable for the specified subindex (as int) or name (as string).

iter(record)

Return an iterator over the subindexes from the record.

subindex in record

Return True if the subindex (as int) or name (as string) exists in the record.

len(record)

Return the number of subindexes in the record.

values()

Return a list of canopen.sdo.SdoVariable in the record.

class canopen.sdo.SdoArray(sdo_node, od)[source]
od

The canopen.objectdictionary.ODArray associated with this object.

array[subindex]

Return the canopen.sdo.SdoVariable for the specified subindex (as int) or name (as string).

iter(array)

Return an iterator over the subindexes from the array. This will make a SDO read operation on subindex 0 in order to get the actual length of the array.

subindex in array

Return True if the subindex (as int) or name (as string) exists in the array. This will make a SDO read operation on subindex 0 in order to get the actual length of the array.

len(array)

Return the length of the array. This will make a SDO read operation on subindex 0.

values()

Return a list of canopen.sdo.SdoVariable in the array. This will make a SDO read operation on subindex 0 in order to get the actual length of the array.

exception canopen.SdoAbortedError(code)[source]

Bases: SdoError

SDO abort exception.

code

Abort code

exception canopen.SdoCommunicationError[source]

Bases: SdoError

No or unexpected response from slave.