URCap Toolbar only works after running a program

I have developed a URCap with an InstallationNode, a ProgramNode and a ToolbarNode for a custom end-effector.

The InstallationNode starts a Python Daemon and sets up RS485 comms over the Tool I/O and RTDE communications.
The ProgramNode works perfectly - I can generate and run a URScript that sends and receives serial commands/responses over the Tool I/O RS485 to our custom end-effector.
The ToolbarNode has some buttons for sending commands on-demand over the Tool I/O RS485 to the custom end-effector.

Testing on a UR5e running Polyscope 5.18:

  • From a fresh start, if I start the Python Daemon, RS485 and RTDE comms in the InstallationNode, and I open the Toolbar and press any of the buttons, not only does it not work, but Polyscope freezes completely and I have to restart the controller.
  • However, from a fresh start, if I start the Python Daemon, RS485 and RTDE comms in the Installation Node, and I run a program (any program on; even if it just contains a Wait command), then launch the Toolbar, it works perfectly.

The URCap adds the following preamble to the urscript via my InstallationNodeContribution class:

@Override
public void generateScript(ScriptWriter writer){
	if (isDaemonRunning()){
		writer.assign("RPC", "rpc_factory(\"xmlrpc\", \"http://127.0.0.1:" + XmlRpcDaemonInterfact.RPC_PORT + "/RPC2\")");
		writer.appendLine("set_tool_communication(True,115200,0,1,1.5,3.5");
		writer.appendLine("RPC.serialStart()");
	}
}

I suspect that these few lines are why the Toolbar works after running a program. Is this a fair assumption?

In the Toolbar, I am already checking that the serial port is open, that rtde is running and that the xmlrpcserver is reachable. So it seems to me that the only thing left to do is “set_tool_communication”, but I can’t find the Java equivalent of this.

Any help is greatly appreciated.

Can you post what commands you’re sending when you press the buttons on the toolbar that causes it to lock up? Like are you using script communication to send the commands? Stuff in the generateScript() methods get run when you press play, so for example, if you click a button on your toolbar BEFORE pressing play, it may be that you’re trying to access the variable “RPC” which won’t exist because you haven’t run that “writer.assign” line at that point.

Hi Eric,

The XmlRpcClient is initialised as follows:

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

XmlRpcClient client;
Integer RPC_PORT = 40406;
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setEnabledForExtensions(true);
try {
	config.setServerURL(new URL("http://" + host + ":" + port + "/RPC2"));
} catch (MalformedURLException e) {
	e.printStackTrace();
}
config.setConnectionTimeout(5000); // 5 s
client = new XmlRpcClient();
client.setConfig(config);

Before the button in the Toolbar is even enabled, I call the following functions, which are returning true (where client is the XmlRpClient which was initialised above):

client.execute("isReachable", new ArrayList<String>());
client.execute("isRtdeRunning", new ArrayList<String>());

and in my python daemon there is:

toolCom = rs485Communication()

server.register_function(toolCom.isReachable, "isReachable")
server.register_function(toolCom.isRtdeRunning, "isRtdeRunning")

class rs485Communication():
	def __init__(self):
		self.rtdeConn = rtde.RTDE(LOCALHOST, RTDE_PORT)
		configFile = './rtde_config.xml'
		conf = rtde_config.ConfigFile(configFile)
		self.stateNames, self.stateTypes = conf.get_recipe('state')
 
	def isReachable(self):
		return True
  
	def isRtdeRunning(self):
		return self.rtdeConn.is_connected()

So, if isReachable and isRtdeRunning are executing and returning true, wouldn’t that mean that the RPC has been initialised correctly?

A button press in the Toolbar is executing a command in the XmlRpcClient - for example:

try {
	ArrayList<String> args = new ArrayList<String>();
	Object result = client.execute("gripper_get_imu", args);
	return processArrayListDouble(result);
} catch (XmlRpcException e) {
	System.err.println("Failed result in gripper_get_imu");
} catch (UnknownResponseException e) {
	System.err.println("Unknown response in gripper_tet_imu");
}

And in the python daemon, there is the following:

server.register_function(gripper.get_imu, "gripper_get_imu")

If it is indeed the writer.assign that is missing when the Toolbar loads, how can I access this in the ToolbarContribution - where does the writer come from?

Thanks,
Heba.

Looked up the set_tool_communication method and I agree with you that this is likely the problem. Or at least the reason it works AFTER you run the program. BEFORE you run the program, the functionality is not “Enabled” but after you run that URScript, then the interface is “Turned on.”

Poking around at the API (Universal Robots - URCap - API Reference Docs) you can search for “AnalogInputModeConfigFactory” which sounds like it might be doing what you’re looking for.

Otherwise, you can likely use the Script Communicator Classes (GitHub - BomMadsen/URCap-ScriptCommunicator: Exemplification of how to communicate with URControl from a URCap) to send the URScript command directly to turn it on.

An update:

I tried implementing the Script Communication example in it’s simplest form within my project. In the openView of my Toolbar Contribution, I added the following, but it didn’t wok (no exceptions raised, but no idea if it is sending anything through the socket or executing the script commands). As far as I can tell, the script I am sending is identical to the script preamble that the Installation is adding to all scripts:

try{
	String TCP_IP = "127.0.0.1";
	int TCP_port = 30002;//XmlRpcContactileDaemonInterface.RPC_PORT
	
	String command = "def "; // send as primary
	command += "myCustomToolbarScript():\n"; // program name
	command += "RPC = rpc_factory(\"xmlrpc\", \"http://127.0.0.1:40406/RPC2\")";
	command += "set_tool_communication(True,115200,0,1,1.5,3.5)"; // command content
	command += "RPC .serialStart()";
	command += "sleep(1)";
	command += "end\n";
	// Create a new Socket Client
	Socket sc = new Socket(TCP_IP, TCP_port);
	if (sc.isConnected()){
		// Create stream for data
		DataOutputStream out;
		out = new DataOutputStream(sc.getOutputStream());
		// Send command
		out.write(command.getBytes("US-ASCII"));
		out.flush();
		// Perform housekeeping 
		out.close();
	}
	sc.close();
} 
catch (IOException e){
	System.err.println(e);
}

Is there something wrong the above?

I’ve also tried to get my head around the AnalogInputModeConfigFactory etc, but I’ve been going around in circles… It looks like ToolIOInterfaceControllable.setAnalogInputModeConfig(AnalogInputModeConfig config) is what I’m after, but ToolIOInterfaceControllable and AnalogInputModeConfig are both interfaces… I can’t find any actual implemented classes based on these interfaces - where are the objects that I would need to modify in order for any of my changes to take effect?

Not too sure on the socket structure. I usually use the classes directly instead of setting up my own sockets. URCap-ScriptCommunicator/com.jbm.urcap.sample.scriptCommunicator/src/main/java/com/jbm/urcap/sample/scriptCommunicator/communicator/InterfaceTester.java at master · BomMadsen/URCap-ScriptCommunicator · GitHub

You can look through the interface tester to see examples of how to set it up. You may need to add a call to the “.setAsPrimary()” if it needs to be in the primary thread. But since you aren’t consuming any physical time, it’s probably fine to call “.setAsSecondary()” instead.

As for the Java side, I couldn’t tell ya. I came to the same conclusion and was just hoping you knew more Java than I did and could make sense of it :sweat_smile:

On the Java side: :rofl: but also :face_with_diagonal_mouth: It makes me feel a little bit better that I didn’t miss anything obvious.

For the socket stuff - all that setAsPrimary() does is add the prefix "def " to the command instead of the prefix "sec ", which I already did. I might try using the classes as is instead of implementing it myself, but also…

I have discovered that even if set_tool_communication is called in URScript (this also goes for set_voltage which sets the tool output voltage (0/12/24 V)) it is not reflected in the Installation->Tool I/O

I think, rather than try to do this programmatically, I will just instruct users to set the tool communication via the Installation->Tool I/O menu. They already have to access this menu to set the output voltage, so :woman_shrugging:t3:

Yeah I’ve definitely noticed that the UI won’t often reflect changes made via script sent from URCaps. I think Robotiq also instructs their users to switch it manually. I tend to hold Robotiq in high regard since they make some nice stuff, so if they do something a certain way, I’m usually fine to settle for that too lol