UnderAutomation
有问题吗?

[email protected]

联系我们
UnderAutomation
⌘Q
Universal Robots SDK documentation
Open and edit program and installation files
Documentation home

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?

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:

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:

_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:

Members of Common.GlobalVariable :
public class GlobalVariable : GlobalVariableValue {
// Variable name
public string Name { get; }
// Last time the variable was sampled
public TimeSpan Time { get; }
}
Members of Common.GlobalVariableValue :
public class GlobalVariableValue {
// Estimate variable value from its string representation
public static GlobalVariableValue Parse(string message)
// 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
public bool ToBool()
// 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
public float ToFloat()
// 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
public int ToInt()
// Returns an array of GlobalVariableValue if Type is List. Else, null is returned
public GlobalVariableValue[] ToList()
// 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
public Array ToMatrix()
// Returns a Pose if Type is Pose. Else, null is returned
public Pose ToPose()
// Returns a string that describes the variable, regardless of its type
public override string ToString()
// Type of a variable
public GlobalVariableTypes Type { get; }
// Value of the variable
public object Value { get; }
}
Members of Common.GlobalVariableTypes :
public enum GlobalVariableTypes {
// Variable value is bool
Bool = 4
// Variable value is float
Float = 6
// Variable value is int
Int = 5
// Variable value is an array : GlobalVariableValue[]
List = 2
// Variable value is a matrix
Matrix = 7
// Variable value is null, the value has not been assigned yet
None = 0
// Variable value is a UnderAutomation.UniversalRobots.Pose
Pose = 3
// Variable value is a System.String
String = 1
}
Members of PrimaryInterface.GlobalVariables :
public class GlobalVariables {
// Indicates which decoder is used used to read variables according to firmware version
public GlobalVariablesFirmwareVersion FirmwareVersion { get; }
// Returns a list of all variables declared in the robot
public GlobalVariable[] GetAll()
// Get a variable by its name. Null is returned if the variable doesn't exist
public GlobalVariable GetByName(string name)
// Event raised whan the variable list changed. For example, after a program starts
public event EventHandler<GlobalVariablesEventArgs> ListUpdated
// Return a string where each line contains type, name and variable value
public override string ToString()
// Event raised at 10Hz when variable values are updated
public event EventHandler<GlobalVariablesEventArgs> ValuesUpdated
}

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


轻松将 Universal Robots、Fanuc、Yaskawa 或 Staubli 机器人集成到您的 .NET、Python、LabVIEW 或 Matlab 应用程序中

UnderAutomation
联系我们定价 • 经销商报价•订单Legal

© All rights reserved.