# How to add a node via external buttons

**URL:** <https://forum.universal-robots.com/t/how-to-add-a-node-via-external-buttons/18557>\
**Category:** URCap Development\
**Created:** [January 10, 2022, 8:44pm UTC](https://forum.universal-robots.com/t/how-to-add-a-node-via-external-buttons/18557 "2022-01-10T20:44:53Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![eric.feldmann](https://avatars.discourse-cdn.com/v4/letter/e/94ad74/32.png) [@eric.feldmann](https://forum.universal-robots.com/u/eric.feldmann)\
**Post date:** [January 10, 2022, 8:44pm UTC](https://forum.universal-robots.com/t/how-to-add-a-node-via-external-buttons/18557/1 "2022-01-10T20:44:53Z")

</div>

I’ve got some custom nodes, and I’m wondering how people are able to create nodes with external inputs, such as buttons mounted near the tool flange, and using the Tool IO. Is there a thread that is constantly monitoring the state of the Tool IO or something? Likewise, how would you go about capturing waypoint data with a press of a button instead of using the getRobotMovementCallback()s?

---

<div class="post-metadata">

**Author:** ![fujikit](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.universal-robots.com/fujikit/32/6042_2.png) [@fujikit](https://forum.universal-robots.com/u/fujikit)\
**Post date:** [January 11, 2022, 9:16am UTC](https://forum.universal-robots.com/t/how-to-add-a-node-via-external-buttons/18557/2 "2022-01-11T09:16:30Z")

</div>

Hi,

Maybe I think that it can be realized by using RTDE.

1. watching the values of tcp pose and values of tool IO.
2. set tcp pose into new waypoint node when detecting on of the IO.

Please see my github repositories how to monitor of IOs.

---

<div class="post-metadata">

**Author:** ![anon84921795](https://avatars.discourse-cdn.com/v4/letter/a/ee7513/32.png) [@anon84921795](https://forum.universal-robots.com/u/anon84921795)\
**Post date:** [February 2, 2022, 11:11am UTC](https://forum.universal-robots.com/t/how-to-add-a-node-via-external-buttons/18557/3 "2022-02-02T11:11:34Z")

</div>

Hi!

I am facing the same problem.

Is there a way, in your opinion, to achieve this result via XMLRPC?

---

<div class="post-metadata">

**Author:** ![eric.feldmann](https://avatars.discourse-cdn.com/v4/letter/e/94ad74/32.png) [@eric.feldmann](https://forum.universal-robots.com/u/eric.feldmann)\
**Post date:** [February 2, 2022, 3:45pm UTC](https://forum.universal-robots.com/t/how-to-add-a-node-via-external-buttons/18557/4 "2022-02-02T15:45:50Z")

</div>

Possibly, I don’t know. I ended up going with my initial thought (using a thread in Java to monitor the state of a Tool IO). Right or wrong, it works. Had to go down a lot of rabbit holes to get it functioning, but it got there in the end.

```auto
import java.util.Collection;
import java.util.Iterator;

import com.ur.urcap.api.domain.io.DigitalIO;
import com.ur.urcap.api.domain.io.IO;
import com.ur.urcap.api.domain.io.IOModel;
import com.ur.urcap.api.domain.io.ModbusIO;

public class IOHelper {

	private final IOModel ioModel;

	public IOHelper(final IOModel ioModel) {
		this.ioModel = ioModel;
	}

	public DigitalIO[] getDigitalInputs() {
		final Collection<DigitalIO> ioCollection = ioModel.getIOs(DigitalIO.class);
		ioCollection.removeIf(n -> !n.isInput());
		final int inputSize = ioCollection.size();
		final Iterator<DigitalIO> itr = ioCollection.iterator();
		final DigitalIO[] inputList = new DigitalIO[inputSize];

		for (int i = 0; i < inputSize; i++) {
			inputList[i] = itr.next();
		}
		return inputList;
	}
	
	
	
	public DigitalIO[] getDigitalOutputs() {
		final Collection<DigitalIO> ioCollection = ioModel.getIOs(DigitalIO.class);
		ioCollection.removeIf(DigitalIO::isInput);
		final int outputSize = ioCollection.size();
		final Iterator<DigitalIO> itr = ioCollection.iterator();
		final DigitalIO[] outputList = new DigitalIO[outputSize];

		for (int i = 0; i < outputSize; i++) {
			outputList[i] = itr.next();
		}
		return outputList;
	}

	public ModbusIO[] getModBusInputs() {
		final Collection<ModbusIO> ioCollection = ioModel.getIOs(ModbusIO.class);
		ioCollection.removeIf(n -> !n.isInput());
		final int inputSize = ioCollection.size();
		final Iterator<ModbusIO> itr = ioCollection.iterator();
		final ModbusIO[] inputList = new ModbusIO[inputSize];

		for (int i = 0; i < inputSize; i++) {
			inputList[i] = itr.next();
		}
		return inputList;
	}

	public ModbusIO[] getModBusOutputs() {
		final Collection<ModbusIO> ioCollection = ioModel.getIOs(ModbusIO.class);
		ioCollection.removeIf(ModbusIO::isInput);
		final int outputSize = ioCollection.size();
		final Iterator<ModbusIO> itr = ioCollection.iterator();
		final ModbusIO[] outputList = new ModbusIO[outputSize];

		for (int i = 0; i < outputSize; i++) {
			outputList[i] = itr.next();
		}
		return outputList;
	}

	public DigitalIO getSpecificDigitalIO(final String defaultName) {
		final Collection<DigitalIO> ioCollection = ioModel.getIOs(DigitalIO.class);
		final int ioCount = ioCollection.size();

		if (ioCount > 0) {
			final Iterator<DigitalIO> ioItr = ioCollection.iterator();
			while (ioItr.hasNext()) {
				final DigitalIO thisIO = ioItr.next();
				final String thisDefaultName = thisIO.getDefaultName();
				if (thisDefaultName.equals(defaultName)) {
					return thisIO;
				}
			}
		}
		return null;
	}
	
	public IO getSpecificGPIO(final String defaultName) {
		final Collection<IO> ioCollection = ioModel.getIOs();
		final int ioCount = ioCollection.size();

		if (ioCount > 0) {
			final Iterator<IO> ioItr = ioCollection.iterator();
			while (ioItr.hasNext()) {
				final IO thisIO = ioItr.next();
				final String thisDefaultName = thisIO.getDefaultName();
				if (thisDefaultName.equals(defaultName)) {
					return thisIO;
				}
			}
		}
		return null;
	}
	
	

	public ModbusIO getSpecificModBusIO(final String signalName) {
		final Collection<ModbusIO> ioCollection = ioModel.getIOs(ModbusIO.class);
		final int ioCount = ioCollection.size();
		if (ioCount > 0) {
			final Iterator<ModbusIO> ioItr = ioCollection.iterator();
			while (ioItr.hasNext()) {
				final ModbusIO thisIO = ioItr.next();
				final String thisSignalAddress = thisIO.getName();
				if (thisSignalAddress.equals(signalName)) {
					return thisIO;
				}
			}
		}
		return null;
	}

}

```

Here’s a class file that can get you access to the IO from within Java. I used this function to grab the tool io:

```auto
getSpecificDigitalIO("tool_out[0]")

```

You’ll notice in this case I used the OUTPUT, instead of the input. That’s just so I can easily trigger it in my simulator. On the real robot, I would change this to tool\_in[0].

Then I just put a Timer that rolls over ever 100ms that checks for changes of that output and reacts accordingly.

You’ll have to use java.awt.EventQueue.invokeLater() in order to set anything in the DataModel, since the Thread does not count as a UI, so Polyscope will throw a fit if you try to edit the datamodel or program tree from inside it.

You’ll have to send a script command via socket to the robot using “get\_actual\_tcp\_pose()” and get the result back to store into the datamodel. You can download the script communication classes here:

> [@URCap Sample: URCap-ScriptCommunicator](https://forum.universal-robots.com/t/urcap-sample-urcap-scriptcommunicator/8460):
>
> Dear community, I have forked Jacobs URCap-ScriptCommunicator and added the framework to proxy URScript functions from Java. So far it is only a subset of the functions that are implemented yet. I hope you will add the functions when you need is there and then share it with the rest of the community! Description of functionality: This sample implements a Java class to: Send URScript commands for immediate execution by URControl Extract a variable from URScript to Java Proxy URScript functio…
