Skip to content
smhty edited this page Dec 7, 2018 · 57 revisions

Initialization

For interacting with the API, the first step is to create and initialize a new Dorna object. Dorna object has some default configuration, but we can initialize it with our own customized configuration file, and pass in a path to a customized configuration file during the initialization as a parameter.

Creating a Dorna object

Dorna(config_path = None)

Input

  • config_path (optional) - string: Path to a customized configuration.

Return

Return an instance of the Dorna class (Dorna object).

Example

# import Dorna class
from dorna import Dorna

# create a Dorna object and name it robot
robot = Dorna()

# or
#robot = Dorna("path_to_a_customized_config.yaml")

Connection

After the initialization step, we need to establish a communication link between the Dorna object and the robot controller box. There are set of methods available for this purpose. 

Listing USB ports

.port_list()

Return Return the name of all available USB ports in a JSON array format.

Example

# list all USB ports
robot.port_list()
#'["COM1", "COM15"]'

Updating firmware

.update_firmware(port_name = None , firmware_path = None)

Update and install the robot firmware.

Notice: In the Linux systems, make sure to install the BOSSA utility software before running the .update_firmware method. For installing the BOSSA run the following command in the terminal.

sudo apt-get install bossa-cli

Input

This method takes two optional inputs:

  • port_name (optional) - string: Name of the USB port connected to the robot. If no USB port is passed as an argument, then the Dorna object automatically finds the first valid USB port, and updates the robot connect to that port.
  • firmware_path (optional) - string: Path to the firmware binary file (.bin file). If the firmware path is not given, then the default firmware that comes with the API package will be installed.

Return

Return a JSON object with two keys "status" and "message":

  • "status": If the update process is successful then the value assigned to the "status" is 0, otherwise it is 100.
  • "message": A string message that provides additional information about the update process.

Example

# robot is connected to COM1
robot.update_firmware()
#'{"status": 0, "message": "firmware updated"}'

# another example
# the robot is connected to COM1
robot.update_firmware(port_name = "COM15")
#'{"status": 100, "message": "USB port stopped working, try again"}'

Connecting to the robot

.connect(port_name = None)

Establish the connection between the Dorna object and the robot.
Notice: The connection process can take few seconds. During the connection process, the connection status of the robot is 1 (connecting). If the connection process is successful then the connection status of the robot changes to 2 (connected). Otherwise, if the connection process is not successful for any reason, then the connection status changes to 0 (disconnect). 

Input

This method takes one optional input:

  • port_name (optional) - string: Name of the robot USB port, in string format. If the port_name is not given, then the API automatically looks for the proper USB port, and connects to the first available robot.

Return Return the robot status via .device.

Example

# start the connection process
robot.connect()
# '{"id": "012-345-6789-abc", "connection": 2, "port": "COM40", "fv": 1.21, "config": "C:\\\\config.yaml", "state": 0}' 

Disconnect From the robot

.disconnect()

Disconnect the Dorna object from the robot. 

Return Return the robot status via .device.

Example

robot.disconnect()
# '{"id": "012-345-6789-abc", "connection": 0, "port": "COM40", "fv": 1.21, "config": "C:\\\\config.yaml", "state": 0}' 

Terminate the object

.terminate()

Completely terminate the Dorna object. After calling this method, the Dorna object is no longer available for any type of communication with the robot. If you need to re establish a connection with the robot again, make sure to make a new Dorna object.
Notice: Dorna object runs multiple threads in the background. So, it is necessary to run this method for every single Dorna object and properly close all the background threads, before closing the program.

Return Return None.

Example

robot.terminate()

Sending commands to the robot

After a successful connection, the robot is ready to receive and execute commands. Each command is a JSON object with three main keys (for more information on the list of available commands, visit the commands page):

  • "command": Name of the command.
  • "prm": Parameters associated to that command.
  • "fulfill": Whether to ignore error in this command (True), or pause if any error happened (False).

Each Dorna object has a queue (submission queue) which is responsible for holding submitted commands. Commands in the submission queue will be sent to the robot one by one.
After submitting commands, the API assign additional keys to each command, in addition to the initial keys. The keys and the value assigned to them are (including the initial keys):

  • "command"
  • "prm"
  • "fulfill"
  • "id": A unique id number assign to each individual command. Ids are not consecutive, but they are increasing non negative integer numbers. Using the id number we can track each individual command in real time.
  • "error": Error number associated to the command. 0 means no error (default), and anything nonzero represents an error.
  • "message": Holds the error message.
  • "state": State of the command. Each command has three main states. This key holds the state number of the command (see Fig. 1). The valid states are:
    • 0: The command is in the submission queue, and has not been processed by the robot yet.
    • 1: The command is being processed by the robot.
    • 2: The command process has been finished.

path_joint
Fig. 1: The general architecture of a command submission. First, a command is submitted, and it goes into a submission queue and waits there for its turn (state 0). The robot takes, processes and executes the command (state 1). Finally, when the execution of a command is over then the command process is done (state 2).

Here are the main methods, for playing, pausing, and halting commands.

Playing commands

.play(commands , append = True)

Use this method to submit commands to the submission queue.
Notice: We can group multiple commands together as an array, and feed them all to the submission queue, instead of sending them one by one. The main benefit of sending multiple commands especially for the "move" command at once, is that the robot can plan all the motions ahead of time and execute a better (smoother) motion.

Input

This method has two inputs:

  • commands (required) - different formats: This represents the commands we are submitting to the submission queue, and can have different formats. The valid formats are listed here:
    • JSON object, or Python dictionary : If there is only one command to play, we can send it individually as a JSON object, or use it equivalent Python dictionary to represent the command (json.loads).
    • JSON array, or Python list of dictionaries: Whether there are multiple commands, or just one single command for the submission (play). We can format them as a JSON array, where each element in the array is a valid command. Another option is to represent the array of commands as a list of dictionaries (json.loads).
  • append (optional) - True or False: It means whether we want the commands to append to the current commands in the submission queue or not. True is the default value and it will append the commands to the submission queue. False will flush the submission queue, run the .halt method, and add the input commands to the submission queue.

Return

If the submission is successful then it will return a JSON array with the list of submitted commands via .command. Otherwise, it will return a JSON object explaining the error.

Example

# turn on the laser, and turn off the output 1
robot.play({"command": "set_io", "prm": {"laser":1, "out2": 0}})
# '[{"id": 125, "state": 0, "error": null, "message": null, "command": "set_io", "fulfill": true, "prm": {"laser": 1, "out2": 0}}]'

# move j0 by 10 degrees
robot.play({"command": "move", "prm": {"movement": 1, "path": "joint", "j0": 10}})
# '[{"id": 127, "state": 0, "error": null, "message": null, "command": "move", "fulfill": true, "prm": {"movement": 1, "path": "joint", "j0": 10}}]'

Pause Commands

.pause()

Flush and return every all the commands from the submission queue. Notice that the .pause method does not necessarily stop the robot instantly.

Return

Return a JSON array with the list of all commands in the submission queue (commands with state 0).

Halt the robot

.halt()

Stop all the motions, and flush every commands from the submission queue and the robot (commands with state 0 and 1).

Property

General status

.device()

Return the general status of the robot.

Return

A JSON object that contains multiple keys. If a value assigned to a key is null, then the status of that key is unknown.

  • "id": The id of the robot in string format, or null.
  • "connection": The connection status of the robot. Either 0, 1, or 2.
    • 0: The Dorna object is disconnected from the robot.
    • 1: The Dorna object is connecting to the robot.
    • 2: The Dorna object is connected to the robot.
  • "port": The name of the USB port in string format, or null.
  • "fv": A number that represents the firmware version of the robot, or null.
  • "config": Path to the configuration file in string format, or null.
  • "state": State of the robot. Either 0, 1 or null:
    • 0: The robot has finished executing all the commands. This basically means that no command with state equal to 0 or 1.
    • 1: The robot is running some commands. This basically means that there are some commands with state equal to 0 or 1.
    • null: The state is unknown.

Example

robot.device()
# '{"id": "012-345-6789-abc", "connection": 2, "port": "COM40", "fv": 1.21, "config": "C:\\\\config.yaml", "state": 0}' 

Summary

Key Value Note
"id" string or null id of the robot
"connection" 0 = disconnected, 1 = connecting or 2 = connected the connection status
"port" string or null USB port name
"fv" number or null firmware version
"config" string or null path to the configuration file
"state" 0 = not busy, 1 = running or null = unknown state of the robot

Position

.position(space = "joint")

Return the current position of the robot in a JSON array format. The potion can be returned either in the joint coordinate system or the Cartesian coordinate system (xyz coordinate system).

Input

The .position method takes one optional input called space. The space variable specifies the coordinate system of the returned position. If the input space is not set then by default space is equal to "joint".

  • space (optional) - string: The coordinate system of the returned position, and it can be either "joint" (the default value), or "xyz":

Return

The .position method returns the position of the robot in a JSON array format. The length of the returned array depends on the number of axes in the robot.

  • If space = "joint", then .positon returns the position in the joint coordinate system in the form of [j0, j1, j2, j3, j4] or [j0, j1, j2, j3, j4, j5] for a robot with five or six axes, respectively.
  • If space = "xyz", then .position returns the position in the Cartesian coordinate system in the form of [x, y, z, a, b] or [x, y, z, a, b, c] for a robot with five or six axes, respectively.

Example

# position in the joint coordinate system
robot.position()
# '[0, 0, 0, 0.0, 0.0]'
# j0 = 0, j1 = 0, j2 = 0, j3 = 0, j4 = 0 

# position in the Cartesian coordinate system
robot.position("xyz")
# '[19.499, 0.0, 8.111, 0.0, 0.0]'
# x = 19.499, y = 0.0, z = 8.111, a = 0.0, b = 0.0

IO status

.io()

Return the current IO status of the robot. This includes the value of: inputs, mode of inputs, outputs, mode of outputs, laser and servo.

Return

The .io() method returns a JSON object.
The keys and the values assigned to them are listed here:

Key Value Note
"outN" 0 = off, 1 = on, null = unknown Get the value for the output N, for N from 1 to 4
"doNmo" 0= active low, 1 = active high, null = unknown Get the mode for the output N, for N from 1 to 4
"inN" 0 = off, 1 = on, null = unknown Get the value for the input N, for N from 1 to 4
"diNmo" 0= active low, 1 = active high, null = unknown Get the mode for the input N, for N from 1 to 4
"laser" 0 = off, 1 = on, null = unknown Get the laser status
"servo" Any number from 0 (all open) to 1000 (all closed), or null = unknown Get the servo value

Example

robot.io()
# '{"out1": 1, "out2": 1, "out3": 1, "out4": 1, "in1": 0, "in2": 0, "in3": 0, "in4": 1, "do1mo": 1, "do2mo": 1, "do3mo": 1, "do4mo": 1, "di1mo": 0, "di2mo": 0, "di3mo": 0, "di4mo": 1, "servo": 550, "laser": 1}'

Commands status

.command(prm)

Return a JSON array that contains submitted commands that are matching the given pattern. The pattern is either based on the command id or the command state.

Input

The input parameter prm can be a JSON object, or its equivalent Python dictionary. prm has only one key, and the key is either "id" or "state".

  • "id": The value assigned to this key is an array of command ids (numbers) that we are looking for. The method searches and finds commands that match one of the given ids array, and returns them all in a JSON array.
  • "state": The value assigned to this key is an array of valid command states. The method searches and finds commands that match one of the given states array, and returns them in a JSON array.
    Notice: The valid state for a submitted command is 0, 1 or 2.

Return

Return a JSON array, where each element in the array is a command matching the prm pattern. Notice: If no command matches the input pattern prm, then the method returns an empty array ([]).

Example

# find commands with id = 2, 3 
robot.command({"id":[2, 3]})
# '[{"id": 2, "state": 2, "error": 0, "message": null, "command": "g2core", "fulfill": true, "prm": "{line:n}"}, {"id": 3, "state": 2, "error": 0, "message": null, "command": "g2core", "fulfill": true, "prm": "{id: n, fv:n}"}]'

# find commands with state = 2 
robot.command({"state":[2]})
# '[{"id": 2, "state": 2, "error": 0, "message": null, "command": "g2core", "fulfill": true, "prm": "{line:n}"}, {"id": 3, "state": 2, "error": 0, "message": null, "command": "g2core", "fulfill": true, "prm": "{id: n, fv:n}"}, {"id": 5, "state": 2, "error": 0, "message": null, "command": "g2core", "fulfill": true, "prm": "{sr: n}"}]'

Homing

The term homing in this context refers to a process that puts the absolute machine coordinates to a known position. Each joint j0, j1, j2, j3 and j4 is either homed 1, or not homed 0, and there are several methods available here to home a joint and set the absolute position for that.
Notice: The homing status of j3 and j4 are coupled to each other. This means, they are both either homed (1), or not homed (1), and homing one of them also home the other one.

Homing status of the joints

.homed()

Return the homing status of the robot in a JSON object.

Return

The returned object has four keys "j0", "j1", "j2", "j3" and "j4", and the value assign to each key indicates the homing status for that joint. The values are:

  • 0: The associated joint is not homed yet.
  • 1: The associated joint is homed.
  • null: The homing status of the associated joint is unknown.
Key Value Note
"jN" 0 = not homed, 1 = homed, null = unknown homing status of jN, for N from 1 to 4

Example

robot.homed()
# all joints are homed except j1
# '{"j0": 1, "j1": 0, "j2": 1, "j3": 1, "j4": 1}'

Home a joint

.home(joint)

It will run the homing process for the given joint, and return the homing status via .homed.

Input

The input is required and it can be one of the joints "j0", "j1", "j2", "j3" or "j4".

Return

If the homing process is successful, then the method return the homing status via .homed. Otherwise, it will return None.

Example

# homing j1
robot.home("j1")
# all joints are homed now, including j1
# '{"j0": 1, "j1": 1, "j2": 1, "j3": 1, "j4": 1}'

Manually home the Joints

.set_joint(joints)

This method sets the absolute position for the set of input joints.
Notice: After running this method all the joints available in the input will be homed. So, this can be used as a way to home the robot without running the actual homing process.

Input

The input joints is required for this method. Input joints specifies the set of joints that we want to set the absolute position for, and the values assigned to each one of these joints. We can pass in the joints in different formats:

  • JSON object, or Python dictionary : Here the keys are a set of joints that are subjected (j0, j1, j2, j3, j4), and the value assign to each joint are the absolute position for that joint. For example {"j0": 100, "j4":10}, sets j0 to 100 and j4 to 10, and keeps the rest of the joints intact.
  • JSON array, or Python list : A JSON array (or its equivalent Python list) with size less than or equal to 5, where the index N in the array is the absolute value for the joint N (jN). For example [100, 0, 10], sets j0 to 100, j1 to 0, j2 to 10, and keeps the rest of the joints intact.

Return

If the process is successful, then the method return the homing status via .homed. Otherwise, it will return None.

Example

robot.position("joint")
# [0, 0, 0, 0, 0]

# Now change the value for j0
robot.set_joint([0])
# or
# robot.set_joint({"j0": 0})
# '{"j0": 1, "j1": 0, "j2": 0, "j3": 0, "j4": 0}'

Calibration

.calibrate(joints)

This method is basically equivalent to .set_joint. In addition to that, the true values assigned to each joint will be saved in the config object. These values can be used later to initialize the value for each joint after the [homing process][#Home-a-joint].
Notice: We can only run this method if all the joints in the robot are already homed.

Input

The input is similar to the input in .set_joint.

Return

If the process is successful, then the method return the current position in the joint coordinate system via [.position][#position]. Otherwise, it will return None.

Configuration

The robot configuration object is a JSON object with multiple keys, that serves as variable to hold the main features of the robot. During the initialization, the robot reads the configuration file and initializes the configuration object. Each key in this object represents one of the main features of the robot, and the value assigned to each key, can be a number, string, array or even a JSON object.
Methods in this section provide access to view, edit and manipulate the configuration object. For more detail about the description and format of each key inside the configuration object visit the configuration page.

Robot configuration

.config()

Return the robot configuration object in a JSON object format.

.save_config(save_path = None)

Write and save the robot configuration object into a YAML format configuration file located at save_path.
The input save_path is optional and it is a string holding the path to the new configuration file. If the save_path is not given then the robot overwrites the already existed configuration file.
This method returns the robot general status via .device.

Number of axes

.axis()

Return the number of axes in the robot in a JSON object format.

.set_axis(prm)

Set the number of axes in the robot.
The input parameter prm is required and it is either a JSON object, or its equivalent python dictionary. The input format is {"number": nmbr}, where nmbr is the number of axes and it is either 5 or 6.
This method returns the axes information via .axis.

Example

robot.axis()
# '{"axis": {"number": 5}}' 

# change number of axes to 6
robot.set_axis({"number": 6})
# '{"axis": {"number": 6}}' 

Unit system

.unit()

Return the unit system of the robot in a JSON object format.

.set_unit(prm)

Set the unit system of the robot.
The input parameter prm is required and it is either a JSON object, or its equivalent python dictionary equivalent. The input format is {"length": l_unit}, where the l_unit is the length unit system and it is either "mm" or "inch".

The method returns the unit information via .unit.

Example

robot.unit()
# '{"unit": {"length": "inch"}}'

robot.set_unit({"length": "mm"})
# '{"unit": {"length": "mm"}}'

Joints limit

.limit()

Return the robot joints limits information in a JSON object format.

.set_limit(prm)

Set the joints limits of the robot.
The input parameter prm is required and it is either a JSON object, or its equivalent python dictionary.
The input keys are a set of joints "j0", "j1" and "j2", and the value assigned to each key (joint) is an array of size 2 with the lower and upper limits in degree (see Example). The method returns the joints limit information via .limit.

Example

robot.limit()
# '{"j0": [-175.0, 175.0], "j1": [-175.0, 160.0], "j2": [-130.0, 130.0]}'

# change the limit only for j0
robot.set_limit({"j0": [-10.0, 10.0]})
# '{"j0": [-10.0, 10.0], "j1": [-175.0, 160.0], "j2": [-130.0, 130.0]}'

Toolhead

.toolhead()

Return the dimension of the toolhead in a JSON object format.

.set_toolhead(prm)

Set the dimension of the toolhead. Notice that, to run this method you need to be connected to the robot. Also, this method interrupts and halts any command running by the robot.
The input is a JSON object, or its equivalent python dictionary, {"x": x_toolhead}. Here, x_toolhead is the length of the toolhead in the robot length unit system. The method returns the toolhead information via .toolhead.

Example

robot.toolhead()
# '{"toolhead": {"x": 1.74}}'

# change the toolhead length to 2 inches
robot.set_toolhead({"x": 2})
# '{"toolhead": {"x": 2}}'

Default speed

.default_speed()

Return the default speed of the robot in a JSON object format.

.set_default_speed(prm)

Set the default speed of the robot.
The input parameter prm is required and it is either a JSON object, or its equivalent python dictionary. The input keys are a set of the two coordinate systems "joint" and "xyz", and the value assigned to each key (coordinate) is a positive number (see Example). The method returns the default speed information via .default_speed.

Example

robot.default_speed()
# '{"default_speed": {"xyz": 100, "joint": 1000}}'

# change the default speed of the joints to 500 deg/min
robot.set_default_speed({"joint": 500})
# '{"default_speed": {"xyz": 100, "joint": 500}}'

Default jerk

.default_jerk()

Return the default jerk of the robot in a JSON object format.

.set_default_jerk(prm)

Set the default jerk of the robot.
The input parameter prm is required and it is either a JSON object, or its equivalent python dictionary. The input keys are a set of the two coordinate systems "joint" and "xyz", and the value assigned to each key (coordinate) is an array of size 5 or 6 (depending on the number of axes) of positive numbers (see Example).
The method returns the default jerk information via .default_jerk.

Example

robot.default_jerk()
# '{"default_jerk": {"xyz": [50, 50, 50, 300, 300, 300], "joint": [300, 300, 300, 300, 300, 300]}}'

# change the default jerk of in the x direction to 100 unit/min^3
robot.set_default_jerk({"xyz": [100, 50, 50, 300, 300]})
# '{"default_jerk": {"xyz": [100, 50, 50, 300, 300], "joint": [300, 300, 300, 300, 300]}}'

Motion parameters

.motion()

Return the motion parameters of the robot in a JSON object format.

.set_motion(prm)

Set the motion parameters of the robot. Notice that, to run this method you need to be connected to the robot. Also, this method interrupts and halts any command running by the robot. The input parameter prm is required and it is either a JSON object, or its equivalent python dictionary. The valid input keys are "jt", "gpa" and "ct". For more information about valid value assign to each key visit the configuration page.
The method returns the motion information via .motion.

Example

robot.motion()
# '{"motion": {"jt": 1, "gpa": 2, "ct": 0.01}}'

# make the motions smoother by increasing jt
robot.set_motion({"jt": 3})
# '{"motion": {"jt": 3, "gpa": 2, "ct": 0.01}}'

Helper Methods

In this section we have provided few methods that make interaction with the robot easier.

Move

.move(prm, fulfill = True, append = True)

This method is basically equivalent to .play({"command": "move", "prm": prm, "fulfill": fulfill}, append).
The prm parameter can be given in a JSON object, or its equivalent python dictionary.

Set IO

.set_io(prm, fulfill = True, append = True)

This method is basically equivalent to .play({"command": "set_io", "prm": prm, "fulfill": fulfill}, append). The prm parameter can be given in a JSON object, or its equivalent python dictionary.