MotionPlus EtherCAT API
Overview
These functions control the interface of the MotionPlus EtherCAT master to the servo drives. Functions include starting and stopping the master and configuring external axes driven by EtherCAT.
Note
For developers implementing third party URCaps that depend on the EtherCAT URScript API, there are some important considerations when calling these functions through the primary interface or through any preamble delivered by a third party URCap’s installation node. See here for details.
URScript Functions
Calling EtherCAT Functions In Third Party URCaps
The EtherCAT functions provided by the MotionPlus URCap can be used by third party URCaps, however, there are some known limitations and workarounds that third party developers should be aware of:
Calling EtherCAT Functions from a URCap’s Installation Node Preamble Contribution:
PolyScope does not guarantee the order of URCap installation node contributions to the URScript preamble. This presents a problem in the scenario where a third party URCap has a contribution that calls functions from the MotionPlus EtherCAT contribution, but Polyscope may have placed the MotionPlus contribution after the third party URCap call which would result in an error during execution
The workaround is for the third party URCap installation node’s generateScript()
method to check if Polyscope has already added the EtherCAT API to the program and add it to the preamble if it hasn’t been. To accomplish this, 3rd party developers can find the EtherCAT API implementation placed in /usr/local/motionplus/ethercat_definitions.script. The ethercat_definitions.script file contains a UUID that looks like this: # UUID: UR_ETHER_09823745092847509284753
. The third party installation node can find the UUID in the preamble generated by Polyscope and add it if it’s not there. Here’s an example J ava implementation of an installation node generateScript() method that accomplishes this :
@Override
public void generateScript(ScriptWriter writer) {
String line = null;
try {
String preambleFileContents = new String(
Files.readAllBytes(Paths.get("/usr/local/motionplus/ethercat_definitions.script")));
boolean ethercatPreambleAlreadyIncludedByPolyscope = false;
// Look for the UUID signature in the preamble file.
final Pattern pattern = Pattern.compile("# UUID:\\s+([A-Za-z0-9]+(_[A-Za-z0-9]+)+)", Pattern.CASE_INSENSITIVE);
final Matcher matcher = pattern.matcher(preambleFileContents);
// If the UUID was found then, look for it in the preamble created by Polyscope
// so far to see if it has already been included.
if (matcher.find()) {
final String currentPolyscopePreamble = writer.generateScript();
final String foundUUIDString = preambleFileContents.substring(matcher.start(), matcher.end());
// See if the UUID string is already in the Polyscope preamble, if so, then we
// assume that the motionplus preamble doesn't need to be added again.
ethercatPreambleAlreadyIncludedByPolyscope = currentPolyscopePreamble.contains(foundUUIDString);
}
// If the UUID string hasn't been found, then add the MotionPlus preamble to the
// Polyscope preamble line by line to ensure proper URScript line formatting.
if (!ethercatPreambleAlreadyIncludedByPolyscope) {
BufferedReader bufReader = new BufferedReader(new StringReader(preambleFileContents));
while ((line = bufReader.readLine()) != null) {
writer.appendLine(line);
}
}
// The 3rd party contribution can be added here now that the EtherCAT API
// has been placed in the URScript file
} catch (IOException e) {
e.printStackTrace();
}
}
The following imports will need to be added to the top of the java implementation file:
import com.ur.urcap.api.domain.script.ScriptWriter
import java.io.BufferedReader;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
Note: The MotionPlus Installation Node looks to see if the EtherCAT API has already been added to the preamble by a third party URCap. If it’s already there, then it’s not added again.
Calling EtherCAT Functions in a Primary Interface Program
The EtherCAT API is not included in any programs run over the primary interfaces. To call EtherCAT API methods in primary interface programs, they must include the API before they are called in the program. This can be accomplished by prepending the contents of the EtherCAT API found in /usr/local/motionplus/ethercat_definitions.script
to the URScript program.
Here is example Java code that sends a primary program to the controller that starts the EtherCAT master if it isn’t already started, enables an axis called “axis1”, and then presents the user with a popup that displays if the axis is enabled.
public void runPrimaryProgram() {
String primaryProgram = null;
// Construct the primary program to be sent to the controller
try {
// Grab the EtherCAT API definitions from the filesystem
String preambleFileContents = new String(
Files.readAllBytes(Paths.get("/usr/local/motionplus/ethercat_definitions.script")));
StringBuilder programBuilder = new StringBuilder();
programBuilder.append("def myPrimaryProgram():\n"); // primary programs are placed inside a URScript function, the
// name doesn't matter
// Write the EtherCAT API preamble line by line into the program with whitespace
// to maintain proper indentation. The controller reads an unindented "end" as
// the end of the program, so it's important that proper indentation of the
// EtherCAT preamble and third party code is maintained. (It also improves
// readability of logfiles.)
BufferedReader bufReader = new BufferedReader(new StringReader(preambleFileContents));
String line = null;
while ((line = bufReader.readLine()) != null) {
programBuilder.append(" " + line + "\n");
}
////// Start third party code here ////////
programBuilder.append(" if (not ethercat_is_master_running()):\n");
programBuilder.append(" ethercat_start()\n");
programBuilder.append(" end\n");
programBuilder.append(" ethercat_enable_axis(\"axis1\")\n");
programBuilder.append(" popup(ethercat_is_axis_enabled(\"axis1\"))\n");
////// End third party code here ////////
programBuilder.append("end\n"); // the unindented "end" marks the end of the primary program
primaryProgram = programBuilder.toString();
} catch (IOException e) {
System.err.println("Failed to construct the primary program.");
return;
}
// Send the program to the controller
try {
Socket socket = new Socket("127.0.0.1", 30001); // primary interface is port 30001
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
outputStream.write(primaryProgram.getBytes("US-ASCII"));
outputStream.flush();
socket.close();
} catch (IOException e) {
System.err.println("Failed to write the primary program to the socket.");
}
}
The following imports will need to be added to the top of the java implementation file:
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.DataOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.net.Socket;
Note: The controller only runs URScript primary programs when the robot is powered on. Also, if this code is being run as part of a URCap GUI (e.g., called when pressing a button), then it should be run by a Java thread to ensure that the GUI stays responsive as in the example below:
public void runPrimaryProgramFromThread() {
new Thread(new Runnable() {
@Override
public void run() {
runPrimaryProgram();
}
}).start();
}