UnderAutomation
Any question?

[email protected]

Contact us
UnderAutomation
⌘Q

Reading & Writing Global Variables

Learn how to read and manage global variables (program and installation) in the Universal Robots controller using the Dashboard Server Protocol and Primary Interface. Explore the GlobalVariable class, handle variable events, and test it with a Windows example.

  • What's a Variable in This Chapter?
  • Reading Variables with Dashboard
  • Reading Variables with Primary Interface
  • Writing Variables
  • The Hidden Trick
  • No Global Variable Writing in a Secondary Program
  • Best Practices for Exchanging Values with Your Program
  • Try It Out with the Windows Example!
  • Available Classes

🌍 What's a Variable in This Chapter?

In this chapter, when we say "variable," we're talking about global variables in the UR controller. These can be program variables or installation variables.

In our library, regardless of the protocol used to handle variables, they are represented by the GlobalVariable class, which contains both the name and value of the variable.
This class extends GlobalVariableValue, which only holds the value. Simple, right? 🚀


📡 Reading Variables with Dashboard

The Dashboard Server Protocol lets you query the robot for a variable's value.

The function that makes this magic happen is GetVariable. It returns a GlobalVariableValue object containing the name and value of the variable. The type? It's automatically estimated from the value! 🧠✨

using UnderAutomation.UniversalRobots;
using UnderAutomation.UniversalRobots.Common;
class DashboardVariable
{
static void Main(string[] args)
{
var robot = new UR();
// Dashboard is enabled by default
robot.Connect("192.168.0.1");
// Read variable called "myVar"
var request = robot.Dashboard.GetVariable("myVar");
if (request.Succeed)
{
GlobalVariable variable = request.Value;
// variable.Name
// variable.Type
// variable.Value
// variable.ToMatrix();
// variable.ToFloat();
// variable.To...();
}
}
}

🔄 Reading Variables with Primary Interface

The Primary Interface is a bit more dynamic, it raises an event whenever a variable's value changes or when the variable list is updated.
This means the library always keeps track of the latest received values for each variable, so you can access their name, type, and value at any time. 🚦

Heads-up! If your application connects while a program is running, you'll only get the list of variables when a change occurs.
That means the list might initially be empty, because the Primary Interface only reacts to updates! ⏳

💡 Good to know: The library adapts to different controller firmware versions.
Since version 3.2, and later 5.9, the way variables are decoded has changed. But don't worry, it's completely seamless for developers! 🎩✨

Two events help you stay updated:

  • 📝 ListUpdated → Triggered when the variable list changes.
  • 🔔 ValuesUpdated → Triggered when a variable's value changes.

The Primary Interface has a GlobalVariables property, which gives you access to the list of variables and the associated events.

using UnderAutomation.UniversalRobots;
using UnderAutomation.UniversalRobots.Common;
using UnderAutomation.UniversalRobots.PrimaryInterface;
class PrimaryInterfaceVariable
{
static void Main(string[] args)
{
var robot = new UR();
// Primary Interface is enabled by default
robot.Connect("192.168.0.1");
// Be notified when the list of variables changes
robot.PrimaryInterface.GlobalVariables.ListUpdated += GlobalVariables_ListUpdated;
// Be notified when at least one variable changes value
robot.PrimaryInterface.GlobalVariables.ValuesUpdated += GlobalVariables_ValuesUpdated;
// Get the list of all variables
GlobalVariable[] variables = robot.PrimaryInterface.GlobalVariables.GetAll();
if (variables.Length == 0) return;
// Get first variable
var variable = variables[0];
// Get variable name
string name = variable.Name;
// Get variable generic value
object value = variable.Value;
// Get its value according to its type
switch (variable.Type)
{
case GlobalVariableTypes.None:
// Variable is empty or doesn't exist
break;
case GlobalVariableTypes.String:
string stringValue = variable.ToString();
break;
case GlobalVariableTypes.List:
GlobalVariableValue[] listValue = variable.ToList();
break;
case GlobalVariableTypes.Pose:
Pose poseValue = variable.ToPose();
break;
case GlobalVariableTypes.Bool:
bool boolValue = variable.ToBool();
break;
case GlobalVariableTypes.Int:
int intValue = variable.ToInt();
break;
case GlobalVariableTypes.Float:
float floatValue = variable.ToFloat();
break;
case GlobalVariableTypes.Matrix:
System.Array matrixValue = variable.ToMatrix();
break;
}
}
private static void GlobalVariables_ValuesUpdated(object sender, GlobalVariablesEventArgs e)
{
// Get new list of variable values
GlobalVariable[] variables = e.Variables;
}
private static void GlobalVariables_ListUpdated(object sender, GlobalVariablesEventArgs e)
{
// Get new list of variable values
GlobalVariable[] variables = e.Variables;
}
}

✍️ Writing Variables

Unfortunately, writing a variable while a program is running is not possible. 😕
This is because none of the protocols exposed by UR controllers allow it.

That said, you can send a script like this:

URScript
global myVar = 12

🛠️ The Hidden Trick 🤫

However, be warned, this will stop the currently running program! ❌
So, if you don't have an active program and just need to set an installation variable, this method works perfectly.
For example, you could initialize an environment variable before starting your program.

Here's a little undocumented trick straight out of nowhere:
To ensure the new installation variable value is actually saved, you need to set _hidden_verificationVariable = 0.
Why? Because this is how Polyscope gets notified of the change! 🧙‍♂️✨

This is an example of how to set the environment variable i_var_1 = 6:

C#
_robot.PrimaryInterface.Script.Send(@"
def SetInstallationVariable():
global _hidden_verificationVariable=0
global i_var_1=6
end");

🚫 No Global Variable Writing in a Secondary Program

Another limitation to keep in mind: writing to global variables is not allowed within a secondary program.
So, if you need to modify variables dynamically, you might need to rethink your approach! 🤔

🔄 Best Practices for Exchanging Values with Your Program

Variables are super handy for sending data from the robot to your software.
As mentioned earlier, when using the Primary Interface, you need to be connected right from the start of program execution to track variables.

But what if you need real-time communication during execution? 🤨
For high-frequency read/write operations, registers are the way to go! 🚀

  • Registers are designed for general-purpose usage.
  • They can be read and written at high speed using RTDE and/or Primary Interface.

So, if you're looking for seamless live data exchange, use registers instead of standard variables! 🏎️💨


🖥️ Try It Out with the Windows Example!

Want to see this in action? A special WinForms page lets you test variable reading live! 🎮
👉 Download it here and give it a spin!


📚 Available Classes

Here are the key classes you'll be working with:

Class
GlobalVariableinherits GlobalVariableValue
C#Python

Describes a global variable

MemberTypeDescription
GlobalVariable()
Constructor
Name
Property
read only
string
Variable name
Time
Property
read only
TimeSpan
Last time the variable was sampled
Class
GlobalVariableValue
C#Python

Describes a typed variable value

MemberTypeDescription
GlobalVariableValue()
Constructor
Type
Property
read only
GlobalVariableTypes
Type of a variable
Value
Property
read only
object
Value of the variable
Parse(string)
Method
static
GlobalVariableValue
Estimate variable value from its string representation
ToBool()
Method
bool
Returns variable value if type is Bool. Il type is Float or Int, it returns True if value is not 0. Else, it returns false
ToFloat()
Method
float
Returns variable value if type is Float. Il type is int, it casts it to float. If Type is bool, it returns 1 or 0. Else it returns NaN
ToInt()
Method
int
Returns variable value if type is Int. Il type is Float, it tries to cast it to int. If Type is bool, it returns 1 or 0. Else it returns 0
ToList()
Method
GlobalVariableValue[]
Returns an array of GlobalVariableValue if Type is List. Else, null is returned
ToMatrix()
Method
Array
Return variable value GlobalVariable[,] if variable is a matrix. First dimension is row index and second dimension is column index. Use GetLength(0) to get row number and GetLength(1) to get column count
ToPose()
Method
Pose
Returns a Pose if Type is Pose. Else, null is returned
ToString()
Method
string
Returns a string that describes the variable, regardless of its type
Enum
GlobalVariableTypes
C#Python

Possible types of a variable

NameValueDescription
Bool
4
Variable value is bool
Float
6
Variable value is float
Int
5
Variable value is int
List
2
Variable value is an array : GlobalVariableValue[]
Matrix
7
Variable value is a matrix
None
0
Variable value is null, the value has not been assigned yet
Pose
3
Variable value is a UnderAutomation.UniversalRobots.Pose
String
1
Variable value is a System.String
Class
GlobalVariables
C#Python

List of all global variables

MemberTypeDescription
FirmwareVersion
Property
read only
GlobalVariablesFirmwareVersion
Indicates which decoder is used used to read variables according to firmware version
ListUpdated
Event
EventHandler<GlobalVariablesEventArgs>
Event raised whan the variable list changed. For example, after a program starts
ValuesUpdated
Event
EventHandler<GlobalVariablesEventArgs>
Event raised at 10Hz when variable values are updated
GetAll()
Method
GlobalVariable[]
Returns a list of all variables declared in the robot
GetByName(string)
Method
GlobalVariable
Get a variable by its name. Null is returned if the variable doesn't exist
  • name : Variable name, not case sensitive
ToString()
Method
string
Return a string where each line contains type, name and variable value

Now you're all set to handle variables like a pro! 🚀 Happy coding! 🎉


Easily integrate Universal Robots, Fanuc, Yaskawa, ABB or Staubli robots into your .NET, Python, LabVIEW or Matlab applications

UnderAutomation
Contact usLegal

© All rights reserved.