Use Case 02: Waterfall
Waterfall is a educative use case with a simple concept and easy to reproduce. It was first deployed in the LocalSEA testbed of CEA List, then its components was dockerized using Docker to be able to test in other environments.
Description
Given a waterfall consisted of multiple stairs. When pouring the water into a stair, the water will go down stair-by-stair until the final one. The use case mimic the mechanism of the waterfall. Figure 1 illustrates this concept.

There are five software components using five network protocols: CANopen, Modbus TCP, OPC UA FX, ROS 2, and EtherNet/IP Class 1, represent five stairs of the waterfall. When a trigger send a message to a stair, it will trigger its lower stair by sending a message to this lower one. For example, when the stair OPC UA FX is triggered, it will trigger the stair ROS 2; then, the stair ROS 2 will trigger the stair EtherNet/IP.
Deployment Instructions
Figure 2 shows the topology of the waterfall use case.
There are seven components: the NPB, five components for five stair
applications using the five protocols, and a component running as
the trigger. The trigger and the five stairs connect to the NPB.
All components are containerized into Docker images.
To ease the deployment, the Docker images for both amd64 and arm64 are prepared in ROS6GBridge UC02 kit.

Note: The official version of this use case supports only four lastest stairs. The CAN Open stair will be put as a bonus.
This use case requires at least two devices, for example, one computer (amd64) and one Raspberry Pi (arm64). While the first device runs NPB and the trigger, the second runs the stairs. Figure 3 illustrates the AAS information model that is used to generate bridge NPB.

The four basic steps are as follows.
Step 1: Download and Load Docker files
User can download the ROS6GBridge UC02 kit, then extract it using the command:
$
unzip UC02_kit.zip
User need to copy all arm64 files (file with arm in name) to the device using architecture arm64. The other files are for amd64.
Each device needs to load its corresponding docker images. In this example, the computer load NPB and Trigger docker images:
$
docker load -i npb_brx_img.tar.gz
$docker load -i pourer_mtcp_img.tar.gz
and the Raspberry Pi loads the docker images of stairs:
$
docker load -i stair_mtcp_img_arm.tar.gz
$docker load -i stair_uafx_img_arm.tar.gz
$docker load -i stair_ros2_img_arm.tar.gz
$docker load -i stair_eip_img_arm.tar.gz
Step 2: Run Docker for stairs
Each stair may need a specific configuration to run properly.
a. Modbus TCP stair
Modbus TCP stair requires the address of NPB bridge as input. For example, the address of NPB bridge is 192.168.56.11. Run the following command:
$
docker run -it --net=host --rm stair_mtcp:0.2.arm /app 192.168.56.11
The expected successful output is Server MODBUSTCP: port 502
showing that
the Modbus TCP stair is listening at port 502.
b. OPC UA FX stair
OPC UA FX stair requires the network interface that connect to the bridge as input. For example, the network interface is eth0. Run the following command:
$
docker run -it --net=host --cap-add=NET_ADMIN --rm stair_uafx:0.2.arm /app eth0
The expected successful output is Server OPC UA FX: port 4801
showing
that the OPC UA FX stair is listening at port 4801.
c. ROS2 stair
ROS2 stair requires some input parameters. Run the following command:
$
docker run -it --net=host --rm stair_ros2:0.2.arm /bin/bash -c "export ROS_DOMAIN_ID=0 && source /opt/ros/humble/setup.bash && source /workspace/install/setup.bash && ros2 run stair led_waterfall"
The expected successful output is Server ROS2: ROS_DOMAIN_ID=0
.
d. EtherNet/IP stair
EtherNet/IP stair requires the network interface that connect to the bridge as input. For example, the network interface is eth0. Run the following command:
$
docker run -it --net=host --rm stair_eip:0.2.arm /app eth0
The expected successful output is Server EtherNet/IP: port 2222
showing that
the EtherNet/IP stair is listening at port 2222.
Step 3: Run NPB Docker
Users need to create a configuration file application.properties which is the input for the NPB Docker. In this example, the address of the Raspberry Pi is 192.168.56.13 and the network interface for the connection with it is eth0. The content of the file is as follows.
app.name=npb_brxfpga
app.version=v1.0
app.sdn.agent.interface=eth0
app.sdn.agent.endpoint=ws://192.168.56.11:8080
ros2.interface=eth0
ros2.domain.id=0
modbustcp.interface=eth0
modbustcp.endpoint=modbus-tcp://192.168.56.13:502
ethernetip.interface=eth0
ethernetip.endpoint=eip-tcp://192.168.56.13:44818
ethernetip.data.endpoint=eip-udp://192.168.56.13:2222
ethernetip.to.connection.point=100
ethernetip.to.elements.range=32
ethernetip.ot.connection.point=150
ethernetip.ot.elements.range=32
uafx.interface=eth0
uafx.multicast.endpoint=udp://224.0.0.1:4801
Run NPB bridge using the following command:
cat application.properties | docker run -i --rm --net=host --cap-add=NET_ADMIN npb_brx:0.4 bash -c "tee application.properties && java -jar app.jar"
The expected successful output is =========== BRx ON
with errors
displayed on the prompt.
Step 4: Trigger a stair
A stair can be triggered using Pourer Docker.
The trigger needs three inputs which are:
- Address of the bridge: in this example, it is 192.168.56.11.
- Unit identifier of the stair: 41 (Modbus TCP), 96 (OPC UA FX), 31 (ROS2),
or 60(EtherNet/IP).
- Value: 0 (false) or 1 (true).
Figure 4 shows the result after triggering the stair Modbus TCP with the following command:
$
docker run -it --net=host --rm pourer_mtcp:0.1 /app 192.168.56.11 41 1

Note: All stairs will be triggered once except stair EtherNet/IP which will be loop. The loop of this last stair can only be stopped by triggering it with the value False.
(Bonus) CANOpen SDO
CANOpen is a protocol for CAN bus. Thus, it does not work with Ethernet natively. To test a CAN bus communication, there are two solutions. First, it requires a module to convert from one socket type to CAN bus. For example, it is MCP2515 CAN Controller in the case of Raspberry Pi. Second, it is possible to use a software tunnel running in the two ends of the communication. In both cases, users must raise the vcan interface with the following commands:
$
sudo modprobe vcan
$sudo ip link add dev vcan0 type vcan
$sudo ip link set vcan0 mtu 16
$sudo ip link set up vcan0
The following is content of tunnel.py running on the computer.
#!/usr/bin/python3
import can, socket, json
import threading
import signal
import os
def signal_handler(sig, frame):
os._exit(0)
signal.signal(signal.SIGINT,signal_handler)
bus = can.interface.Bus(channel='vcan0', interface='socketcan')
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
SRC_PORT = 8811
SRC_ADDR = "0.0.0.0"
DES_PORT = 8813
DES_ADDR = "192.168.56.13"
def forward_data():
while True:
msg = bus.recv()
data = json.dumps({'arbitration_id': msg.arbitration_id,
'data': list(msg.data),'is_extended_id': msg.is_extended_id}).encode()
sock.sendto(data, (DES_ADDR, DES_PORT))
thread = threading.Thread(target=forward_data)
thread.start()
sock.bind((SRC_ADDR, SRC_PORT))
while True:
data, _ = sock.recvfrom(1024)
msg_data = json.loads(data.decode())
msg = can.Message(
arbitration_id=msg_data['arbitration_id'],
data=msg_data['data'],
is_extended_id=msg_data['is_extended_id']
)
bus.send(msg)
Note: For the
tunnel.py running on Raspberry Pi,
it is necessary to change the values of
SRC_PORT,
DES_PORT, and
DES_ADDR.
After establishing the CAN over Ethernet channel,
the CAN data communication is ready.
The CANOpen implemented in this test follows the simpliest CANOpen
Service Data Object
(SDO) mapping.
Figure 5 illustrates the new AAS information model of bridge NPB including
CANOpen. In detail, a new interface canopen
and a new routing node
brx_70_1_1
are added.

To ease the deployment, an amd64 Docker image for the bridge and a arm64 Docker image for stair CANOpen are prepared in ROS6GBridge UC02-b kit . Users can reuse other components to test with these two extensions. Figure 6 shows the result when triggering the stair CANOpen. with the following command:
$
docker run -it --net=host --rm pourer_mtcp:0.1 /app 192.168.56.11 70 1

Note: This test requires fundamentally two stairs CANOpen and ModbusTCP.