Dynamixel For Unity Document EN - HackMD

Table of Contents

1. Overview

DynamixelforUnity (D4U) is an asset to easily implement Dynamixel servomotor control within in Unity3D. D4U provides numerous methods to interface with Dynamixel servomotors, enabling you to efficiently and easily connect, control, and read data from a variety of Dynamixel servomotors.

Specificially, D4U focuses on the following feature sets:

  • Automatically load the Control Table of the servomotor
  • Enable simultaneous control of multiple servomotor models.
  • Enable Controlling Dynamixel servomotor with simple declarative code.
  • Abstracts low level servomotor and provides a number of classes to simplify servomotor controls.
  • Enable advanced functions like, batch control of multiple models and unit conversion.
  • Provide low-level communication and servomotor controls within Unity3D (when required).

Therefore, users are able to completely focus on writing all robot control code from within Unity3D, using simple code in C# that can easily be integrated with a variety of applications, games, simulations or other experiences and use cases that leverage Unity3D.

Supported OS

  • Windows

Supported protocol

Supported Dynamixel models

Model compatible with DYNAMIXEL Protocol 2.0.

  • MX-28
  • MX-64
  • MX-106
  • X Series (2X Series included)
  • PRO Series
  • P Series

2. Installation

With the Unity3D project you want to use, double-click DynamixelForUnity.unitypackage, or drag and drop it into the Project window of the Unity3D project. A pop-up will appear, please choose to improt the package and all its contents to your project.

3. License Purchase and Activation

A license must be purchased from HatsuMuv site in order to use D4U with complete expirence. Without a license, you can only use 10 operations for every execution.

After the purcahse, you will recieve a link to a form, where you are required to provide various information, including device ID, which is a unique ID number that is used to link your license to the machine D4U will be used on:
License Registration Form

To generate your device ID and insert it in the above form, click Get DeviceID for Registration in your toolbar. It will automatically copy your device ID to your clip board and shows in consle window. Please follow the instructions shown in the screenshot below:
Getting Device ID

After your purchase D4U, you will recieve an SN by email. To use your SN within D4U, please insert your Email and SN in the D4U verificate method or through the Dynamixel For Unity Component in Unity3D UI as shown below:

To check your verify your activation, simply run your scene, and you can check if the activation is correct or not in consle.

4. Quick Start

Here is a demo that gets and sets the positions of 2 Dynamixel servomotors.

Before Starting, Assigning ID Numbers to Your New DYNAMIXEL Servos

Before you start this demo, you will need to set your Dynamixel Servos with different IDs.

The simplest way to do this is by using ROBOTIS’ DYNAMIXEL Wizard 2.0 Software. Please refers to ROBOTIS website to search for ID

Setting up a new scene

  1. Open a new scene and drag and drop HatsuMuv/DynamixelForUnity/Prefabs/DynamixelForUnity into the hierarchy window.

  1. Select DynamixelForUnity gameobject in Hierarchy menu

  1. In Inspector window, you can find a component called DynamixelForUnity. Enter your Email and SN, and the USB serial port which connected to your Dynamixel servomotor in the Device Name field. (You can find the port name from your Device manager, e.g. “COM3”).

  2. (Optional) If you know the baudrate of the servomotor you want to operate, set the Baud Rate in the inspector of DynamixelForUnity beforehand. If you don’t know, leave it blank, D4U SetUp method will scan for you. (Which can be time comsuming)

  3. “Click Add Component” Button, and input script name as you like (For this time, “Demo”). Then click “New script”.

  1. Double click on the script called Demo written in gray text and wait for a while. Visual studio will open.

Coding C# script

When Visual Studio opens, write as below. This code prints the current positions of two servomotors to Debug.Log and then sets their goal positions to 1024 each.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HatsuMuv.DynamixelForUnity.x64;

public class Demo : MonoBehaviour
{
    DynamixelForUnity d4u;
    
    void Start()
    {
        d4u = GetComponent<DynamixelForUnity>();
        d4u.ConnectDynamixel();
        d4u.SetUp();
       
        // Set operating mode to Position Control Mode
        d4u.SyncSetDataGroupMultiModels("OperatingMode", new uint[] { 3, 3 });
        
        // Torque enable
        d4u.SyncSetDataGroupMultiModels("TorqueEnable", new uint[] { 1, 1 });
        
        // Get and print present position
        int[] presentPosition = d4u.SyncGetSignedDataGroupMultiModels("PresentPosition");
        Debug.Log("PresentPosition: " + string.Join(", ", presentPosition));
    
        // Set goal position
        d4u.SyncSetDataGroupMultiModels("GoalPosition", new uint[] { 1024, 1024 });
        
    }
    
    void OnApplicationQuit()
    {
        // Torque disable
        uint[] torqueEnableCommand = new uint[] { 0, 0 };
        d4u.SyncSetDataGroupMultiModels("TorqueEnable", torqueEnableCommand);    
    }
}

Execution

Return to the Unity screen and click the Play button.

The position of the servomotor will be printed on the console.

5. Script Reference

Select a namespace from the following according to your system configuration.

// Select a namespace which suit for your system (OS)
HatsuMuv.DynamixelForUnity.x64
HatsuMuv.DynamixelForUnity.x86

DynamixelForUnity

DynamixelForUnity is a class provided to control Dynamixel servomotors with declarative program.

Declarative programming: Describe what you want, not how to do it. For more details, please search for ‘Declarative Programming’.

One DynamixelForUnity component manage one port. If you want to control multiple ports simultaneously, please add as many components as the number of ports.

DynamixelForUnity is implementing IControlTableUser.

Flow of Use:

  1. Open a port with ConnectDynamixel.
  2. (Optional) Keep the servomotor ID and model number used in SetUp or SetIDsForUse. This procedure allows for concise writing when sending instructions using only data field names or when sending instructions to all servomotors.
  3. Control the servomotor with methods such as SetData, etc. Note that data in the EEPROM area such as OperatingMode can only be written when the torque is OFF.
  4. At the end of the oparation, perform a termination procedure such as torque disable in the OnApplicationQuit or OnDisable. If the DynamixelForUnity is connected at the time when OnDestroy is called, it will call DisconnectDynamixel.

Here is Example.

using HatsuMuv.DynamixelForUnity.x64;

public class ExampleClass : MonoBehaviour
{
    DynamixelForUnity d4u;

    void Start() {
        d4u = GetComponent<DynamxielForUnity>();

        // If the SN code and email address are not set in the inspector, this code is necessary.
        // d4u.Verificate();
        
        d4u.ConnectDynamixel();
        d4u.SetUp();
        
       // something you want to do.
       d4u.SetData("TorqueEnable", 1, 1);
    }
    
    void OnApplicationQuit() {
       
       // Termination procedure
       d4u.SetData("TorqueEnable", 0, 1)
    }
}

Constant

Constant Value Description
PROTOCOL_VERSION 2 DynamixelForUnity supports protocol version 2.0 only.

Variables

Name Description
showMessage If this is set to true, all execution logs of DynamixelForUnity will be output to
Debug.Log. Errors and warnings are not affected.

Propertyies

Name Description
ControlTables An object that contains controlTable of multiple models. Functions that send commands from data field names refer to this.
BaudRate Returns the current baud rate. Read only.
IDsForUse ID array held in DynamixelForUnity. SetUp method and SetIDsForUse method. Read-only.
ModelNumbers Dictionary<byte, int> type. Represents the model number of the servomotor for which the ID is being held, set by the SetIDsForUse and SetUp methods. Read-only.
ConnectStatus True/false value indicating whether or not there is a connection with the servomotor. Read only.
Varification True/False value indicating whether the license is authenticated. Read-only.

Verificate

  • Declaration
    public bool Verificate(HatsuVerif verif)

  • Argument

    HatsuVerif verif
    Verification class object. Created from the license file path and verification information.
  • Returns
    License validity.

  • Description
    This function is used for validating your license, which will be automatically called (Awake function) if you put DynamxielForUnity in your gameobject as component from beginning. If you new a instant after pressing play, you will need to run this method to validate your license before you start to use D4U’s functions.


  • Declaration
    public bool Verificate(string userEmail, string userSN, bool forceRenew = false)

  • Returns
    License validity.

ConnectDynamixel

  • Declaration
    public bool ConnectDynamixel()
    public bool ConnectDynamixel(string deviceName)
    public bool ConnectDynamixel(BaudRate baudRate)
    public bool ConnectDynamixel(string deviceName, BaudRate baudRate)

  • Argument

    string deviceName
    Port name to connect. ex.) "COM3".
    BaudRate baudRate
    Baud rate to be connected.
  • Returns
    Returns true if the connection succeeds, false otherwise.

  • Description
    Opens a port with the specified baud rate and connects to the Dynamixel servomotor. If no port or baud rate is specified, the value specified in the inspector is used.

ScanInBaudRate

  • Declaration
    public byte[] ScanInBaudRate(BaudRate baudRate, byte[] idsForScan = null)

  • Argument

    BaudRate baudRate
    Baud rate used for scanning.
    byte[] idsForScan
    The ID of the target to be scanned, used to search only for servomotors with a specific ID; if null is specified, all IDs are scanned.
  • Returns
    Byte array of available servomotor IDs.

  • Description
    Ping the Dynamixel servomotor at the specified baud rate and scan it; use the SetBaudRate method to change to the specified baud rate.


  • Declaration
    public byte[] ScanInBaudRate(BaudRate baudRate, byte minIDsForScan, byte maxIDsForScan)

  • Argument

    byte minIDsForScan
    Lower limit of the range for the ID of the object to be scanned. (Included in the range)
    byte maxIDsForScan
    Upper limit of the range for the ID of the object to be scanned. (Included in the range)
  • Returns
    Byte array of available servomotor IDs.

  • Description
    Ping the Dynamixel servomotor at the specified baud rate and scan it, using the SetBaudRate method to change to the specified baud rate. The scan target can be specified in a range.

ScanInBaudRateAsync

  • Declaration
    public async Task<byte[]> ScanInBaudRateAsync(BaudRate baudRate, byte[] idsForScan = null, CancellationToken cancellationToken = default(CancellationToken))

  • Argument

    BaudRate baudRate
    Baud rate used for scanning.
    byte[] idsForScan
    The ID of the target to be scanned, used to search only for servomotors with a specific ID; if null is specified, all IDs are scanned.
    CancellationToken cancellationToken
    Used to cancel a process.
  • Returns
    Byte array of available servomotor IDs.

  • Description
    Asynchronously pings and scans Dynamixel servomotors at the specified baud rate; changes to the specified baud rate using the SetBaudRate method.


  • Declaration
    public async Task<byte[]> ScanInBaudRateAsync(BaudRate baudRate, byte minIDsForScan, byte maxIDsForScan, CancellationToken cancellationToken = default(CancellationToken))

  • Argument

    byte minIDsForScan
    Lower limit of the range for the ID of the object to be scanned. (Included in the range)
    byte maxIDsForScan
    Upper limit of the range for the ID of the object to be scanned. (Included in the range)
    CancellationToken cancellationToken
    Used to cancel a process.
  • Returns
    Byte array of available servomotor IDs.

  • Description

Asynchronously pings and scans Dynamixel servomotors at a specified baud rate, using the SetBaudRate method to change to the specified baud rate. The scan target can be specified in a range.

Ping

  • Declaration
    public bool Ping(byte ID, bool hideErrorMsg = true)

  • Argument

    byte ID
    ID of the target to ping.
    bool hideErrorMsg
    Disable error output on connection failure.
  • Returns
    Whether they are connected.

  • Description
    Ping the specified ID to check if it is connected.

PingGetModelNumber

  • Declaration
    public int PingGetModelNumber(byte ID)

  • Argument

    byte ID
    ID of the target to ping.
  • Returns
    Model number. When communication fails, -1 is returned.

  • Description
    Ping the specified ID to obtain the model number.

GetAllModelNumber

  • Declaration
    public int[] GetAllModelNumber(byte[] ids = null)

  • Argument

    byte[] ids
    The target ID from which the model number is obtained; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Returns
    An array of model numbers. Items for which communication failed are marked with -1.

  • Description
    Ping the specified multiple IDs and return an array of model numbers.

SetControlTable

  • Declaration
    public void SetControlTable(ControlTables controlTables)

  • Argument

    ControlTables controlTables
    The target ID from which the model number is obtained; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Description
    Implementation of IControlTableUser. Sets the control table.

SetUp

  • Declaration
    public byte[] SetUp(BaudRate? baudRate = null, byte[] idsForScan = null, bool scanAllBaudRateIfNotFound = true)

  • Argument

    BaudRate? baudRate
    The baud rate to be scanned first; if null is specified, the BaudRate previously set by Inspector or other means is used.
    byte[] idsForScan
    ID for setup target; if null is specified, scan is performed for all IDs.
    bool scanAllBaudRateIfNotFound
    If no Dynamixel servomotors are found at the first baud rate scanned, scan at all baud rates.
  • Returns
    Byte array of available servomotor IDs.

  • Description
    Scan the dynamixel servomotor with the ScanInBaudRate method and hold the scanned ID as the servomotor to be used with the SetIDsForUse method.

SetUpAsync

  • Declaration
    public async Task<byte[]> SetUpAsync(BaudRate? baudRate = null, byte[] idsForScan = null, bool scanAllBaudRateIfNotFound = true, CancellationToken cancellationToken = default(CancellationToken))

  • Argument

    BaudRate? baudRate
    The baud rate to be scanned first; if null is specified, the BaudRate previously set by Inspector or other means is used.
    byte[] idsForScan
    ID for setup target; if null is specified, scan is performed for all IDs.
    bool scanAllBaudRateIfNotFound
    If no Dynamixel servomotors are found at the first baud rate scanned, scan at all baud rates.
    CancellationToken cancellationToken
    Used to cancel a process.
  • Returns
    Byte array of available servomotor IDs.

  • Description
    Asynchronously scan the dynamixel servomotor with the ScanInBaudRateAsync method and hold the scanned ID as the servomotor to be used with the SetIDsForUse method.

SetIDsForUse

  • Declaration
    public void SetIDsForUse(byte[] idsForUse)

  • Argument

    byte[] idsForUse
    Target ID.
  • Description
    Keep the ID as a target for use and associate it with the model number.

By having DynamixelForUnity retain the servomotor ID and model number, it is possible to send commands using only the data field names, or to write concisely when sending commands to all servomotors.

DisconnectDynamixel

  • Declaration
    public void DisconnectDynamixel()

  • Description
    Close the port.

CloseAndReopenPort

  • Declaration
    public void CloseAndReopenPort(bool withSetBaudRate = true)

  • Argument

    bool withSetBaudRate
    Set again to the immediately previous baud rate.
  • Description
    Close and reopen the port.

RebootDynamixel

  • Declaration
    public void RebootDynamixel(byte[] ids = null)

  • Argument

    byte[] idsForScan = null
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Description
    Reboot the Dynamixel servomotor.

FactoryResetDynamixel

  • Declaration
    public void FactoryResetDynamixel(DynamixelFactoryResetMode mode, byte[] ids = null)

  • Argument

    DynamixelFactoryResetMode mode
    Select whether to reset all values, all values except ID, or all values except ID and baud rate.
    byte[] idsForScan
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Description
    Reset the Dynamixel servomotor to the factory defaults.

SetBaudRate

  • Declaration
    public bool SetBaudRate(BaudRate baudRate)

  • Argument

    BaudRate baudRate
    The baud rate of the target.
  • Returns
    Returns true if successful, false otherwise.

  • Description
    Set the baudrate of the port.

SetData

  • Declaration
    public bool SetData(ushort ADDR, ushort LEN, uint data, byte id)

  • Argument

    ushort ADDR
    Address of the data field to be written. See Control Table of the model.
    ushort LEN
    Size of the data field to be written. See Control Table in the model.
    uint data
    Data to be written.
    byte id
    Target ID.
  • Returns
    Returns true if successful, false otherwise.

  • Description
    Writes data to the Dynamixel servomotor with the specified ID.

Check the Contorol Table from the ROBOTIS e-Manual of each Dynamixel servomotor for the address and length of the data field.


  • Declaration
    public bool SetData(ControlTableAddressInfo addressInfo, uint data, byte id)

  • Argument

    ControlTableAddressInfo addressInfo
    A structure with the address, length, and access for each data field in the Control Table.
    uint data
    Data to be written.
    byte id
    Target ID.
  • Returns
    Returns true if successful, false otherwise.

  • Description
    SetData(ushort ADDR, ushort LEN, uint data, byte id) is used to write data to the Dynamixel servomotor with the specified ID. If the data field is read-only (e.g. present position), this method will not execute the command.


  • Declaration
    public bool SetData(string dataName, uint data, byte id)

  • Argument

    string dataName
    Servomotor control Table data field name. Please refer to using the control table section for more information.
    uint data
    Data to be written.
    byte id
    Target ID.
  • Returns
    Returns true if successful, false otherwise.

  • Description
    SetData(ushort ADDR, ushort LEN, uint data, byte id) is used to write data to the Dynamixel servomotor with the specified ID. If the data field is read-only, it is not executed.

        d4u.SyncGetSignedDataGroupMultiModels("GoalPosition").ToActualNumber(UNIT.POSITION).ToFloatArray(), ct);


The ID and model number must be retained by the SetUp or SetIDsForUse method to be used.

SetSignedData

  • Declaration
    public bool SetSignedData(ushort ADDR, ushort LEN, uint data, byte id)
    public bool SetSignedData(ControlTableAddressInfo addressInfo, int data, byte id)
    public bool SetSignedData(string dataName, int data, byte id)

  • Description
    Writes signed data to the Dynamixel servomotor with the specified ID, see Description of SetData.

GetData

  • Declaration
    public uint GetData(ushort ADDR, ushort LEN, byte id)

  • Argument

    ushort ADDR
    Address of the data field to be rewritten. See Control Table of the model.
    ushort LEN
    Size of the data field to be rewritten. See Control Table in the model.
    byte id
    Target ID.
  • Returns
    Data read. Returns 0 if an error occurs.

  • Description
    Reads the data of the Dynamixel servomotor with the specified ID.

Check the Contorol Table from the ROBOTIS e-Manual of each Dynamixel servomotor for the address and length of the data field.


  • Declaration
    public uint GetData(ControlTableAddressInfo addressInfo, byte id)

  • Argument

    ControlTableAddressInfo addressInfo
    A structure containing the address, length, and access for each data field in the Control Table.
    byte id
    Target ID.
  • Returns
    Data read. Returns 0 if an error occurs.

  • Description
    GetData(ushort ADDR, ushort LEN, byte id) is used to read data of a servomotor by specifying it’s ID.


  • Declaration
    public uint GetData(string dataName, byte id)

  • Argument

    string dataName
    Control Table data field name.
    byte id
    Target ID.
  • Returns
    Data read. Returns 0 if an error occurs.

  • Description
    GetData(ushort ADDR, ushort LEN, byte id) is used to read data from a servomotor by specifying it’s ID.

The ID and model number must be created in using either the SetUp method or SetIDsForUse method to be used.

GetSignedData

  • Declaration
    public int GetSignedData(ushort ADDR, ushort LEN, byte id)
    public int GetSignedData(ControlTableAddressInfo addressInfo, byte id)
    public int GetSignedData(string dataName, byte id)

  • Description
    Reads the signed data of the Dynamixel servomotor with the specified ID, see Description of GetData.

SyncSetDataGroup

  • Declaration
    public bool SyncSetDataGroup(ushort ADDR, ushort LEN, uint[] data, byte[] ids = null)
    public bool SyncSetDataGroup(ControlTableAddressInfo addressInfo, uint[] data, byte[] ids = null)

  • Argument

    ushort ADDR
    Address of the data field to be rewritten. See Control Table of the model.
    ushort LEN
    Size of the data field to be rewritten. See Control Table in the model.
    ControlTableAddressInfo addressInfo
    A structure containing the address, length, and access for each data field in the Control Table.
    uint[] data
    Data array to be written.
    byte[] ids = null
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Returns
    Returns true if successful, false otherwise.

  • Description
    Writes data to multiple servomotors simultaneously using GroupSyncWrite.

SyncSetDataGroupMultiModels

  • Declaration
    public bool SyncSetDataGroupMultiModels(string dataName, uint[] data, byte[] ids = null)

  • Description
    Writes data to multiple servomotors at the same time using GroupSyncWrite method. If the item names on the ControlTable are the same, the data will be sent to different addresses. In that case, call SyncSetDataGroup for each unique address; see Description of SyncSetDataGroup.

The ID and model number must be retained by the SetUp or SetIDsForUse method to be used.

SyncSetSignedDataGroup

  • Declaration
    public bool SyncSetSignedDataGroup(ushort ADDR, ushort LEN, int[] data, byte[] ids = null)
    public bool SyncSetSignedDataGroup(ControlTableAddressInfo addressInfo, int[] data, byte[] ids = null)

  • Description
    Writes signed data to multiple servomotors simultaneously using GroupSyncWrite; see SyncSetDataGroup Description.

SyncSetSignedDataGroupMultiModels

  • Declaration
    public bool SyncSetSignedDataGroupMultiModels(string dataName, int[] data, byte[] ids = null)

  • Description
    Write signed data to multiple servomotors simultaneously using GroupSyncWrite method, see Description of SyncSetDataGroupMultiModels.

The ID and model number must be retained by the SetUp or SetIDsForUse method to be used.

SyncGetDataGroup

  • Declaration
    public uint[] SyncGetDataGroup(ushort ADDR, ushort LEN, byte[] ids = null)
    public uint[] SyncGetDataGroup(ControlTableAddressInfo addressInfo, byte[] ids = null)

  • Argument

    ushort ADDR
    Address of the data field to be read. See Control Table of the model.
    ushort LEN
    Size of the data field to be read. See Control Table in the model.
    ControlTableAddressInfo addressInfo
    A structure containing the address, length, and access for each data field in the Control Table.
    byte[] ids = null
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Returns
    uint array containing the read after executing the SyncGetDataGroup.

  • Description
    Read data from multiple servomotors simultaneously using GroupSyncRead.

SyncGetDataGroupMultiModels

  • Declaration
    public uint[] SyncGetDataGroupMultiModels(string dataName, byte[] ids = null)

  • Description
    Simultaneously read data from multiple servomotors using GroupSyncRead method. If the item names on the ControlTable are the same, the data will be sent to different addresses. In that case, call SyncSetDataGroup for each unique address; see Description of SyncGetDataGroup.

The ID and model number must be retained by the SetUp or SetIDsForUse method to be used.

SyncGetSignedDataGroup

  • Declaration
    public int[] SyncGetSignedDataGroup(ushort ADDR, ushort LEN, byte[] ids = null)
    public int[] SyncGetSignedDataGroup(ControlTableAddressInfo addressInfo, byte[] ids = null)

  • Description
    Read signed data to multiple servomotors simultaneously using GroupSyncRead, see Description of SyncGetDataGroup.

SyncGetSignedDataGroupMultiModels

  • Declaration
    public int[] SyncGetSignedDataGroupMultiModels(string dataName, byte[] ids = null)

  • Description
    Read signed data to multiple servomotors simultaneously using GroupSyncRead, see Description of SyncGetDataGroupMultiModels.

The ID and model number must be retained by the SetUp or SetIDsForUse method to be used.

BulkSetDataGroup

  • Declaration
    public BulkWritePacket BulkSetDataGroup()

  • Returns
    BulkWritePacket object.

  • Description
    Returns a BulkWritePacket object for writing data to multiple servomotors at once using GroupBulkWrite.

GroupBulkWrite is described in a method chain mediated by BulkWritePacket.

BulkGetDataGroup

  • Declaration
    public BulkReadPacket BulkGetDataGroup()

  • Returns
    BulkReadPacket object.

  • Description
    Returns a BulkReadPacket object for reading data in batches to multiple servomotors using GroupBulkRead.

GroupBulkRead is described in a method chain mediated by BulkReadPacket.

Using the Control Table

We created a text file to represent the control table of each Dynamixel servomotor. The control tables map each property name to the corresponding register number within for servomotor model.

The control tables correspond to the servomotor control tables found in ROBOTIS e-Manual.

Please check the control table data under D4U HatsuMuv/DynamixelForUnity/Resources/ControlTables/ and find the corresponding servomotor, as shown in the screenshot below:
ControlTable

The control tables can be used as parameters in a variety of methods in D4U, where you can pass the parameter name as a string to control or get feedback from various servomotors, as shown in the example below

// you may pass a control table parameter to read in the below method, where the control table parameter corresponds to the string representation of the register you need to set/read.  

// This example uses wet a group of data through sync method
SyncGetDataGroupMultiModels("GoalPosition");

Using BulkWritePacket

Executing bulk write includes the following steps:
1- Initiate struct to hold bulk write parameters.
2- Add parameters to the struct.
3- Send the bulkwrite command.
4- (Options) read result of executing the command.

The BulkWritePacket object is used to execute the above four steps by settings its properties and calling its methods as highlighting explained below.

Step 1. Initiate Struct

To initiate the struct to hold the parameters for the writing packet, you must first declare and initialize the relevant BulkWritePacket objects as follows:

// bulk write packet
BulkWritePacket writePacket = dynamixelForUnity.BulkSetDataGroup();

Step 2. Adding Parameters

Upon creating the BulkWritePacket object, the data to be written should be added to the created object as parameters. This can be done as follows:

writePacket.AddParam(addressInfo1, idArray1, data1);
// you may add as many parameters as needed
writePacket.AddParam(addressInfo2, idArray2, data2);
writePacket.AddParam(addressInfo3, idArray3, data3);

Step 3. Sending BulkWrite Command

Upon adding the parameters, the command can be executed by calling the BulkWritePacket object’s Send() method, as shown below:

writePacket.Send();

Step 4. (Optional) Checking results of BulkWrite Command Execution

You may optionally check the status of the command, whether it was successfully executed or not. You can check the property “AllSuccess” which is set to true if the command is successfully executed.

if(writePacket.AllSuccess)
    Debug.Log("Successful");

Alternatively, you can directly place the BulkPacket object in an ‘if’ conditional to check if the command was successful.

if(writePacket)
    Debug.Log("Successful");

Overall, you may execute the four steps in one line efficiently as follows:
Example:

if(dynamixelForUnity
    .BulkSetDataGroup()
    .AddParam(addressInfo1, idArray1, data1)
    .AddParam(addressInfo2, idArray2, data2)
    .AddParam(addressInfo3, idArray3, data3)
    .Send())
    Debug.Log("Successful");

Properties

Name Description
IDParamPair It is of type Dictionary<byte, ParamInfo>. This holds parameters for each ID. ParamInfo contains address, length, communication success, and data to be written. Read-only.
AllSuccess A boolean value indicating whether communication of all parameters was successful. Read only.
HasSent A boolean value indicating whether the command was sent. Read only.

AddParam

  • Declaration
    public BulkWritePacket AddParam(ushort ADDR, ushort LEN, uint[] data, byte[] ids = null)

  • Argument

    ushort ADDR
    Address of the data field to be written. See Control Table of the model.
    ushort LEN
    Size of the data field to be written. See Control Table in the model.
    uint[] data
    Data to be written.
    byte[] id
    Target ID; if null is specified, the IDs held in DynamixelForUnity is targeted.
  • Returns
    Itself.

  • Description
    The information and data of the data field to be written are stored in IDParamPair.


  • Declaration
    public BulkWritePacket AddParam(ControlTableAddressInfo addressInfo, uint[] data, byte[] ids = null)

  • Argument

    ControlTableAddressInfo addressInfo
    A structure containing the address, length, and access for each data field in the Control Table.
    uint[] data
    Data to be written.
    byte[] id
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Returns
    Itself.

  • Description
    AddParam(ushort ADDR, ushort LEN, uint[] data, byte[] ids = null) is used to store the information and data of the data field to be written in IDParamPair. If the data field is read-only, it is not executed.

AddParamSigned

  • Declaration
    public BulkWritePacket AddParamSigned(ushort ADDR, ushort LEN, int[] data, byte[] ids = null)
    public BulkWritePacket AddParamSigned(ControlTableAddressInfo addressInfo, int[] data, byte[] ids = null)

  • Description
    Stores information and signed data of the data field to be written in IDParamPair; see Description in AddParam.

Send

  • Declaration
    public BulkWritePacket Send(bool discardAllWhenErrorHappen = false)

  • Argument

    bool discardAllWhenErrorHappen = false
    If set to ture, if an error occurs during the AddParam operation, the process is aborted without sending a command.
  • Returns
    Itself.

  • Description
    Send GroupBulkWrite command to servomotors based on IDParamPair.

ResetStatus

  • Declaration
    public void ResetStatus()

  • Description
    Reset communication results and transmission flags. The data to be written is not deleted.

Using BulkReadPacket

Executing bulk read includes the following steps:
1- Initiate struct to hold bulkread parameters.
2- Add parameters to the struct.
3- Send the bulkread command.
4- (Options) read result of executing the command.
5- Reading returned values from the servomotors.

The BulkReadPacket object is used to execute the above four steps by settings its properties and calling its methods as highlighting explained below.

Step 1. Initiate Struct

To initiate the struct to hold the parameters for the reading packet, you must first declare and initialize the relevant BulkdReadPacket object as follows:

// bulk read packet
BulkReadPacket readPacket = dynamixelForUnity.BulkGetDataGroup();

Step 2. Adding Parameters

Upon creating the BulkReadPacket object, the data to be read should be added to the created object as parameters. This can be done as follows:

readPacket.AddParam(addressInfo1, idArray1);
// you may add as many parameters as needed
readPacket.AddParam(addressInfo2, idArray2);
readPacket.AddParam(addressInfo3, idArray3);

Step 3. Sending BulkRead Command

Upon adding the parameters, the command can be executed by calling the BulkReadPacket object’s Send() method, as shown below:

readPacket.Send();

Step 4. (Optional) Checking results of BulkRead Command Execution

You may optionally check the status of the command, whether it was successfully executed or not. You can check the property “AllSuccess” which is set to true if the command is successfully executed.

if(readPacket.AllSuccess)
    Debug.Log("Successful");

Alternatively, you can directly place the BulkPacket object in an ‘if’ conditional to check if the command was successful.

if(readPacket)
    Debug.Log("Successful");

Step 5. Reading returned values from the servomotors.

To read the data that was read from the servomotors after executing the bulkread command, you can use the method GetData() of the BulkReadPacket as follows:

// create a uint array to store the results read from the servomotors
uint[] data = readPacket.GetData();

Overall, you may execute the five steps and print out the results as follows:
Example:

if(var readPacket = dynamixelForUnity
    .BulkGetDataGroup()
    .AddParam(addressInfo1, idArray1)
    .AddParam(addressInfo2, idArray2)
    .AddParam(addressInfo3, idArray3)
    .Send())
{
    Debug.Log("Successful");
    uint[] data = readPacket.GetData();
    Debug.Log("Data: " + string.Join(", ", data));
}

Property

Name Description
IDParamPair It is of type Dictionary<byte, ParamInfo>. This holds parameters for each ID. ParamInfo contains address, length, communication success, and data from servomotor. Read only.
AllSuccess A boolean value indicating whether communication of all parameters was successful. Read only.
HasSent A boolean value indicating whether the command was sent. Read only.

AddParam

  • Declaration
    public BulkReadPacket AddParam(ushort ADDR, ushort LEN, byte[] ids = null)

  • Argument

    ushort ADDR
    Address of the data field to be read. See Control Table of the model.
    ushort LEN
    Size of the data field to be read. See Control Table in the model.
    byte[] id
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Returns
    Itself.

  • Description
    The information and data of the data field to be read are stored in IDParamPair.


  • Declaration
    public BulkReadPacket AddParam(ControlTableAddressInfo addressInfo, byte[] ids = null)

  • Argument

    ControlTableAddressInfo addressInfo
    A structure containing the address, length, and access for each data field in the Control Table.
    byte[] id
    Target ID; if null is specified, the ID held in DynamixelForUnity is targeted.
  • Returns
    Itself.

  • Description
    AddParam(ushort ADDR, ushort LEN, byte[] ids = null) is used to store information about the data field to be read in IDParamPair.

Send

  • Declaration
    public BulkReadPacket Send(bool discardAllWhenErrorHappen = false)

  • Argument

    bool discardAllWhenErrorHappen = false
    If set to ture, if an error occurs during the AddParam operation, the process is aborted without sending a command.
  • Returns
    Itself.

  • Description
    Send GroupBulkRead command to Dynamxiel servomotor based on IDParamPair.

GetData

  • Declaration
    public uint[] GetData(bool resetStatus = false)

  • Argument

    bool resetStatus
    If true, the ResetStatus method is called upon exit.
  • Returns
    Data array read.

  • Description
    Retrieve the read data array.

GetSignedData

  • Declaration
    public int[] GetSignedData(bool resetStatus = false)

  • Argument

    bool resetStatus
    If true, the ResetStatus method is called upon exit.
  • Returns
    Data array read.

  • Description
    Retrieve the signed data array that was read.

ResetStatus

  • Declaration
    public void ResetStatus()

  • Description
    Reset communication results and transmission flags. The read data is also deleted.

ParamInfo

Class representing data fields in BulkWritePacket and BulkReadPacket.

Variable

Name Description
address Data address.
length Length of data.
isSuccess Whether the communication was successful or not.
data In case of BulkWritePacket, data to be written; in case of BulkReadPacket, data to be read.

ControlTables

A class that stores the Control Table for each servomotor; the Control Table is initialized by putting text written in the specified format into the constructor argument. The constructor takes either string[] or TextAsset[] as an argument.

Text files of Control Table for DynamxielForUnity compatible models are located in Assets/HatsuMuv/DynamixelForUnity/Resources/ControlTables. See ControlTableInjectorFromResources for usage examples.

ControlTables is the ControlTable of the servomotor to be used during initialization. The first line describes the model name and model number with “:” in between. The other lines describe the itemName, address, length, and access.

ItemName is derived from the item name in the ControlTable on Dynamixel’s model page, with spaces removed.

If the access is read-only, specify ‘R’; if writable, specify ‘RW’.

Lines beginning with “#” or “//” are ignored as comments.

<ModelName>:<ModelName> <ItemName>, <Address>, <Length>, <Access> <ItemName>, <Address>, <Length>, <Access> ...

Property

Name Description
ModelNames This is of type Dictionary<int, string>. It records the correspondence between model numbers and model names from the read text data.

GetAddrssInfo

  • Declaration
    public ControlTableAddressInfo GetAddrssInfo(int modelNumber, string dataName)
    public ControlTableAddressInfo this[int modelNumber, string dataName]

  • Argument

    int modelNumber
    Model Number.
    string dataName
    Data Name.
  • Returns
    ControlTableAddressInfo type representing data field information.

  • Description
    Returns a ControlTableAddressInfo type representing the data field information from the specified model number and data name. The indexer [int modelNubmer, string dataName] also produces the same result.

GetControlTable

  • Declaration
    public Dictionary<string, ControlTableAddressInfo> GetControlTable(int modelNumber)
    public Dictionary<string, ControlTableAddressInfo> this[int modelNumber]

  • Argument

    int modelNumber
    Model number of the subject.
  • Returns
    Dictionary<string, ControlTableAddressInfo> type representing the control table.

  • Description
    Returns a Dictionary<string, ControlTableAddressInfo> type representing the control table from the specified model number. The indexer [int modelNubmer] produces the same result.

Contains

  • Declaration
    public bool Contains(int modelNumber)

  • Argument

    int modelNubmer
    The model number to look up.
  • Returns
    Returns true if the Control Table with the specified model number exists, otherwise returns false.

  • Description
    Returns whether the Control Table with the specified model number exists.


  • Declaration
    public bool Contains(int modelNumber, string dataName)

  • Argument

    int modelNubmer
    The model number to look up.
    string dataName
    Name of the data to be examined.
  • Returns
    Returns true if the Control Table with the specified model number exists and the data field with the specified data name exists, otherwise returns false.

  • Description
    Returns whether a data field with a data name of the specified model number exists.

GetModelsContains

  • Declaration
    public int[] GetModelsContains(string dataName)

  • Argument

    string dataName
    Name of the data to be examined.
  • Returns
    An array of model numbers with data fields of the specified data name in the Control Table.

  • Description
    Returns an array of model numbers that have data fields with the specified data name in the Control Table.

ControlTableAddressInfo

A structure representing information about data fields in the Control Table.

Variable

Name Description
address Data address.
length Length of data.
readWrite True if writable, false if read-only.

IControlTableUser

An Interface to inject control tables, implemented by DynamixelForUnity.

SetControlTables

  • Declaration
    public void SetControlTables(ControlTables controlTables)

Core

Dynamixel SDK compatible class. Put a HatsuVerif object in the constructor and create an instance.

6. Explanation of Example Scene

A sample scene is located within: HatsuMuv/DynamixelForUnity/Example/ExampleScene_x64.unity

This scene has a sample graphical-user interface (GUI) application using that uses DynamixelForUnity to open a com port, scan for servomotors, connect to servomotors, control servomotors and read various information from servomotors that are all displayed on the GUI.

Screen Explanation

  1. Select DynamixelForUnity gameobject in Hierarchy menu

  1. In Inspector window, you can find a component called DynamixelForUnity. Enter your Email and SN, and the USB serial port which connected to your Dynamixel servomotor in the Device Name field. (You can find the port name from your Device manager, e.g. “COM3”).

  2. (Optional) If you know the baudrate of the servomotor you want to operate, set the Baud Rate in the inspector of DynamixelForUnity beforehand. If you don’t know, leave it blank, D4U will scan for you. (Which can be time comsuming)

After setup DynamxielForUnity components, click play, Dynamixel4Unity will automatically attempt to open the designated port and connect to available servomotors.

The screen lists the connected Dynamixel servomotors. The connected baud rate is displayed at the top of the screen.

The read-only data items at the bottom are constantly updated (such as present position) .

The other items are updated when there is a change in the inserted data (for example, to set a new servomotor position).

Hint: If values differ from the actual value, try press the Refresh button to retrieve the data again.

Implementation Explanation

D4UExampleController

Start()

private async void Start()
{
    NeedWait = true;
    
    if (d4u == null)
    {
        Debug.LogError("[DynamixelForUnitySample] DynamixelForUnity is not assigned!");
        return;
    }

    cancellationTokenSource = new CancellationTokenSource();

    var connectResult = await Task.Run(() => InitializeDynamixel(cancellationTokenSource.Token));
    if (connectResult) StartMotorMetrics();

    NeedWait = false;
}

The NeedWait property is externally referenced to play the screen load animation.

DynamixelForUnity (d4u) is expected to be assigned by Inspector.

The cancellationTokenSource is created to interrupt asynchronous tasks.

Connect to the servomotor and execute the initialization method InitializeDynamixel asynchronously and wait for it.

Once the Dynamixel servomotor is connected by InitializeDynamixel, the StartMotorMetricsm method starts a loop that continuously measures the state of the servomotor.


InitializeDynamixel(CancellationToken ct)

private async Task<bool> InitializeDynamixel(CancellationToken ct)
{
    if (d4u == null)
    {
        Debug.LogError("[DynamixelForUnitySample] DynamixelForUnity is not assigned!");
        return false;
    }

    if (!d4u.ConnectStatus)
    {
        var connectResult = d4u.ConnectDynamixel();
        if (!connectResult)
        {
            Debug.LogError("[DynamixelForUnitySample] Dynamixel is not connected. Connect it first.");
            return false;
        }

        await d4u.SetUpAsync(cancellationToken:ct);
    }

    servomotors = new List<DynamixelMotor>();
    ids = d4u.IDsForUse;

    if (ids.Length == 0) return false;

    await GetAllMotorProperty(ct);
    return true;
}

The d4u.ConnectDynamixel method connects to the servomotor. You can also specify a port name and baudrate as arguments. In this case, the values entered in the Unity3D Inspector are ignored.

The SetUpAsync method calls two methods to scan the servomotor and hold the IDs found at once.

  1. Call the ScanInBaudRateAsync method to scan for Dynamixel servomotors at the specified port name and baudrate. If the servomotor is not found, it will start a scan in all baudrates and sets the port to the baudrate at which the servomotor is first found.
  2. Retains the ID and model number of the servomotor found by calling the SetIDsForUse method.

DynamixelForUnity retain servomotor IDs and model numbers, it is possible to send commands using only the data field names, and functions can be written to be concise when sending commands to all the servomotors.

Next, we use get all servomotor properties by calling GetAllMotorProperty method and create a DynamixelMotor instance.


GetAllMotorProperty(CancellationToken ct)

private async Task GetAllMotorProperty(CancellationToken ct)
{
    OperatingMode[] operatingModes = 
        await Task.Run(() =>
            d4u.SyncGetDataGroupMultiModels("OperatingMode")
                .Select(d => (OperatingMode)d)
                .ToArray(),
            ct);

    float[] homingOffsets = await Task.Run(() => d4u.SyncGetSignedDataGroupMultiModels("HomingOffset").ToActualNumber(UNIT.POSITION).ToFloatArray(), ct);
    ...

    for (int i = 0; i < ids.Length; i++)
    {
        DynamixelMotor m;
        if (motors.Count < i + 1) 
        {
            m = new DynamixelMotor(ids[i]);
            servomotors.Add(m);
        }
        else
        {
            m = servomotors[i];
        }
        m.OperatingMode = operatingModes[i];
        m.HomingOffset = homingOffsets[i];
        ...
    }
}

Each and every property of the DynamixelMotor class is obtained by the method SyncGetSignedDataGroupMultiModels. One property is explained using an example.

float[] homingOffsets = 
    await Task.Run(
        () => d4u.SyncGetSignedDataGroupMultiModels("HomingOffset")
            .ToActualNumber(UNIT.POSITION)
            .ToFloatArray(),
        ct
    );

The line that initializes homingOffsets has a line break for clarity.

The second line, Task.Run method, executes the function of the first argument asynchronously in a separate thread.

From the third line, it is the function you want to execute in a separate thread.

d4u.SyncGetSignedDataGroupMultiModels(“HomingOffset”) retrieves the value of the “HomingOffset” data field for all servomotors stored in DynamixelForUnity.

ToActualNumber(UNIT.POSITION) applies units to the raw data obtained from the SyncGetSignedDataGroupMultiModels.

ToFloatArray() converts a double[] to a float[].

MotorMetrics is a similar method that strips some data from GetAllMotorProperty.


StartMotorMetrics()

servomotorMetricsLoop(CancellationToken ct)

StopMotorMetrics()

private void StartMotorMetrics()
{
    if (!d4u.ConnectStatus)
        return;

    cancellationTokenSource = cancellationTokenSource ?? new CancellationTokenSource();
    var cancellationToken = cancellationTokenSource.Token;
    metricsLoop = servomotorMetricsLoop(cancellationToken);
}

private async Task servomotorMetricsLoop(CancellationToken ct)
{
    while (true)
    {
        if (ct.IsCancellationRequested)
            return;

        Debug.Log("[SampleController] Metrics");
        try
        {
            await servomotorMetrics(ct);
        }
        catch (OperationCanceledException)
        {
            Debug.Log("[SampleController] Metrics canceled");
            return;
        }
        catch (Exception e)
        {
            Debug.LogError(e);
            return;
        }
    }
}

private async Task StopMotorMetrics()
{
    if (cancellationTokenSource != null && !cancellationTokenSource.IsCancellationRequested)
    {
        cancellationTokenSource.Cancel();
        cancellationTokenSource.Dispose();
        cancellationTokenSource = null;

        if(metricsLoop != null)
            await metricsLoop;
    }
}

MotorMetricsLoop continues to call servomotorMetrics until it is canceled by CancellationToken. StopMotorMetrics cancels servomotorMetrics and waits for the process to finish.

D4UExampleUI

Generate UI elements. Generates a panel for each servomotor from D4UExampleController and updates those data.

D4UExampleUIElement

It directly controls the fields in each panel; when it receives input from a UI element, it passes the value to D4UExampleContorller.