Skip to content

Cellulo V1 Installation on Raspberry Pi

Victor Borja edited this page Dec 2, 2022 · 1 revision

This guide covers the Cellulo environment installation on a Raspberry Pi (RPi for short) for two purposes:

1. Using the RPi as a connection hub to robots, possibly over multiple adapters (i.e use the RPi as a cellulorobothubd host). This will allow swarm functionality on platforms where this is not supported, namely Windows, MacOS and Android. 2. Developing and deploying Qt and Cellulo apps/components natively on the said RPi.

Building and deploying Qt and Cellulo natively on the RPi was preferred for its simplicity and sustainability over cross-compiling on a powerful host machine, despite the clear disadvantage in the time required to complete this task. If desired, same results can be obtained by cross-compiling via the many (aged) guides found online.

Install option 1: Flash prebuilt image

This is the easy way of obtaining a ready to go RPi with Cellulo on it. You will need:

  • RPi 3 Model B, any other model will not work
  • SD card with at least ~18GB size (16GB will not work)

Instructions:

1. Download the image here: http://icchilisrv1.epfl.ch/files/cellulo/rpi-cellulo-robot-hub.img

2. Plug the SD card in your host machine (Unix-based assumed) and run the following command to flash the image to the SD card:

$ sudo dd if=rpi-cellulo-robot-hub.img of=<sd-card-device-path> bs=4M status=progress

where <sd-card-device-path> is something like /dev/sda or /dev/sdb. You can check which one by running lsblk before and after you plug in the SD card and checking which device is newly added. Be very careful to provide the correct target device as dd can potentially destroy any of your filesystems!

3. Plug your SD card into your RPi and boot. At first boot, the SD card image will be expanded to fit the entire card, which can take a few minutes. You might have to reboot once more when things are done.

4. [Optional] Configure the network by first connecting to the RPi over WiFi (SSID: CelluloRPi, password: cellulo1234, IP of RPi: 192.168.4.1) or over a direct ethernet connection (IP of RPi: 192.168.2.1). You can now SSH into the RPi (username: pi, password: raspberry) to change the default network settings like the IPs, network SSIDs or passwords. See steps 14 and 15 below to see how.

5. [Optional but recommended] If you're going to be using the RPi as a robot hub, disable the internal Bluetooth adapter as its performance seems to be lacking. SSH into the RPi and add the line dtoverlay=pi3-disable-bt at the end of /boot/config.txt. Reboot for the change to take effect. Use external USB dongle adapters for better performance.

6. See below for testing your installation as a hub to connect to robots.

Install option 2: Manual build

This guide was tested:

  • On RPi 3 Model B (I do not recommend doing this on a lower end RPi simply because of the time it takes to build Qt, but it should be possible, see below)
  • With Raspbian Stretch on a 32GB SD card (down to 16GB should also work)
  • With Qt 5.11.1 (this process can be very sensitive to Qt versions to proceed with caution on other untested Qt versions)

Important note: Many of the below steps will require long waiting times, on the order of many hours. Having another task on the side helps.

Instructions:

1. Get the Raspbian Stretch with Desktop image from https://www.raspberrypi.org/downloads/raspbian/ and unzip it.

2. Plug the SD card in your host machine (Unix-based assumed) and run the following command to flash the image to the SD card:

$ sudo dd if=YYYY-MM-DD-raspbian-stretch.img of=<sd-card-device-path> bs=4M status=progress

where <sd-card-device-path> is something like /dev/sda or /dev/sdb. You can check which one by running lsblk before and after you plug in the SD card and checking which device is newly added. Be very careful to provide the correct target device as dd can potentially destroy any of your filesystems!

3. Plug the SD card into your RPi and boot up with a mouse, keyboard and monitor. Connect to the internet (an ethernet connection is highly recommended as there's a lot of stuff to download) during the initial boot and finalize the setup wizard, including the updates.

4. Remove the useless stuff (there may be more or less stuff to remove at the time of following this guide):

$ sudo apt remove libreoffice* minecraft-pi wolfram-engine wolframscript scratch scratch2 sense-hat sense-emu-tools sonic-pi python3-thonny
$ sudo apt autoremove

5. Default swap size is not enough to build Qt. Run:

$ sudo dphys-swapfile swapoff

Then, edit /etc/dphys-swapfile and change the line CONF_SWAPSIZE=100 into CONF_SWAPSIZE=2000. Then, run:

$ sudo dphys-swapfile swapon

Reboot to get the new size in effect.

6. Get all the dependencies to build Qt. Uncomment the deb-src ... line in /etc/apt/sources.list, then run the following:

$ sudo apt update
$ sudo apt install libcurl4-openssl-dev libfontconfig1-dev libdbus-1-dev libfreetype6-dev libudev-dev \
      libicu-dev libsqlite3-dev libxslt1-dev libasound2-dev libavcodec-dev libavformat-dev libswscale-dev \
      libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev gstreamer-tools gstreamer0.10-plugins-ugly \
      gstreamer0.10-plugins-good gstreamer0.10-plugins-base libraspberrypi-dev libpulse-dev libx11-dev \
      libglib2.0-dev freetds-dev libsqlite0-dev libpq-dev libmariadbclient-dev firebird-dev libpng-dev \
      libgst-dev libxext-dev libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 \
      libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm4 \
      libxcb-icccm4-dev libxcb-sync1 libxcb-sync-dev libxcb-render-util0 libxcb-render-util0-dev \
      libxcb-xfixes0-dev libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev libxi-dev \
      libdrm-dev libxcb-xinerama0 libxcb-xinerama0-dev default-libmysqlclient-dev flex gir1.2-gtk-2.0 \
      libatk1.0-dev libaudio-dev libcairo-script-interpreter2 libcairo2-dev libcups2-dev libcupsimage2-dev \
      libgdk-pixbuf2.0-dev libgl1-mesa-dev libglu1-mesa-dev libgraphite2-dev libgtk2.0-dev libharfbuzz-dev \
      libharfbuzz-gobject0 libice-dev libjpeg-dev libjpeg62-turbo-dev libjpeg8 liblcms2-dev \
      libmariadbclient-dev-compat libmng-dev libmng1 libodbc1 libpam0g-dev libpango1.0-dev \
      libpixman-1-dev libreadline-dev libsm-dev libssl1.0-dev libtiff5-dev libtinfo-dev libxcb-dri2-0-dev \
      libxcb-dri3-dev libxcb-present-dev libxcomposite-dev libxcursor-dev libxdamage-dev libxft-dev \
      libxinerama-dev libxml2-utils libxmu-dev libxmu-headers libxrandr-dev libxshmfence-dev libxt-dev \
      libxtst-dev libxv-dev libxxf86vm-dev mesa-common-dev odbcinst odbcinst1debian2 pkg-kde-tools \
      unixodbc-dev x11proto-composite-dev x11proto-damage-dev x11proto-dri2-dev x11proto-gl-dev \
      x11proto-randr-dev x11proto-record-dev x11proto-video-dev x11proto-xf86vidmode-dev \
      x11proto-xinerama-dev gir1.2-atspi-2.0 gir1.2-gst-plugins-base-1.0 gir1.2-gstreamer-1.0 \
      libatk-bridge2.0-dev libatspi2.0-dev libdouble-conversion-dev libegl1-mesa-dev libepoxy-dev \
      libgbm-dev libgles2-mesa-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libgtk-3-dev \
      libinput-dev libmtdev-dev libproxy-dev libqt5clucene5 libqt5designer5 libqt5designercomponents5 \
      libqt5help5 libqt5qml5 libqt5quick5 libqt5quickwidgets5 libqt5webkit5 libwayland-bin libwayland-dev \
      libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev publicsuffix qtchooser qttools5-dev-tools \
      libudev-dev libinput-dev libts-dev libxcb-xinerama0-dev libxcb-xinerama0 libbluetooth-dev bluetooth \
      blueman bluez libusb-dev libdbus-1-dev bluez-hcidump bluez-tools

7. Run the following to get all the Qt sources (took about 30 minutes on a very fast connection):

$ mkdir src
$ cd src
$ git clone git://code.qt.io/qt/qt5.git
$ cd qt5
$ git checkout v5.11.1
$ ./init-repository

8. Run the following to configure the build (took about 20 minutes):

$ ./configure -v \
       -release \
       -opensource -confirm-license \
       -device linux-rasp-pi3-g++ \
       -device-option CROSS_COMPILE=/usr/bin/ \
       -opengl es2 \
       -optimized-qmake \
       -reduce-exports \
       -make libs \
       -nomake examples \
       -no-compile-examples \
       -no-use-gold-linker \
       -skip qtwayland \
       -skip qtwebengine \
       -skip qtscript \
       -prefix /usr/local/qt5 \
       2>&1

At this point, if you are targeting another device than the RPi 3, you should replace the -device linux-rasp-pi3-g++ option with another one, see qtbase/mkspecs/devices/linux-rasp-pi*-g++ for available options. There may be other configure options to tweak depending on the selected device.

After the configuration is done, check the config.summary file for the configured build, it should look like the following:

Building on: linux-g++ (arm, CPU features: <none>)
Building for: devices/linux-rasp-pi3-g++ (arm, CPU features: neon)
Configuration: cross_compile enable_new_dtags largefile neon precompile_header shared rpath release c++11 c++14 c++1z concurrent dbus no-pkg-config reduce_exports release_tools stl
Build options:
  Mode ................................... release; optimized tools
  Optimize release build for size ........ no
  Building shared libraries .............. yes
  Using C++ standard ..................... C++1z
  Using ccache ........................... no
  Using gold linker ...................... no
  Using new DTAGS ........................ yes
  Using precompiled headers .............. yes
  Using LTCG ............................. no
  Target compiler supports:
    NEON ................................. yes
  Build parts ............................ libs
Qt modules and options:
  Qt Concurrent .......................... yes
  Qt D-Bus ............................... yes
  Qt D-Bus directly linked to libdbus .... no
  Qt Gui ................................. yes
  Qt Network ............................. yes
  Qt Sql ................................. yes
  Qt Testlib ............................. yes
  Qt Widgets ............................. yes
  Qt Xml ................................. yes
Support enabled for:
  Using pkg-config ....................... no
  udev ................................... yes
  Using system zlib ...................... yes
Qt Core:
  DoubleConversion ....................... yes
    Using system DoubleConversion ........ yes
  GLib ................................... no
  iconv .................................. no
  ICU .................................... yes
  Tracing backend ........................ <none>
  Logging backends:
    journald ............................. no
    syslog ............................... no
    slog2 ................................ no
  Using system PCRE2 ..................... no
Qt Network:
  getifaddrs() ........................... yes
  IPv6 ifname ............................ yes
  libproxy ............................... no
  Linux AF_NETLINK ....................... yes
  OpenSSL ................................ yes
    Qt directly linked to OpenSSL ........ no
  OpenSSL 1.1 ............................ no
  SCTP ................................... no
  Use system proxies ..................... yes
Qt Gui:
  Accessibility .......................... yes
  FreeType ............................... yes
    Using system FreeType ................ no
  HarfBuzz ............................... yes
    Using system HarfBuzz ................ no
  Fontconfig ............................. no
  Image formats:
    GIF .................................. yes
    ICO .................................. yes
    JPEG ................................. yes
      Using system libjpeg ............... yes
    PNG .................................. yes
      Using system libpng ................ yes
  EGL .................................... yes
  OpenVG ................................. no
  OpenGL:
    Desktop OpenGL ....................... no
    OpenGL ES 2.0 ........................ yes
    OpenGL ES 3.0 ........................ yes
    OpenGL ES 3.1 ........................ yes
    OpenGL ES 3.2 ........................ yes
  Vulkan ................................. no
  Session Management ..................... yes
Features used by QPA backends:
  evdev .................................. yes
  libinput ............................... no
  INTEGRITY HID .......................... no
  mtdev .................................. no
  tslib .................................. yes
  xkbcommon-evdev ........................ no
QPA backends:
  DirectFB ............................... no
  EGLFS .................................. yes
  EGLFS details:
    EGLFS OpenWFD ........................ no
    EGLFS i.Mx6 .......................... no
    EGLFS i.Mx6 Wayland .................. no
    EGLFS RCAR ........................... no
    EGLFS EGLDevice ...................... no
    EGLFS GBM ............................ no
    EGLFS VSP2 ........................... no
    EGLFS Mali ........................... no
    EGLFS Raspberry Pi ................... yes
    EGL on X11 ........................... no
  LinuxFB ................................ yes
  VNC .................................... yes
  Mir client ............................. no
  X11:
    Using system-provided XCB libraries .. yes
    EGL on X11 ........................... no
    Xinput2 .............................. yes
    XCB XKB .............................. yes
    XLib ................................. yes
    XCB render ........................... yes
    XCB GLX .............................. yes
    XCB Xlib ............................. yes
    Using system-provided xkbcommon ...... no
    Native painting (experimental) ....... no
Qt Widgets:
  GTK+ ................................... no
  Styles ................................. Fusion Windows
Qt PrintSupport:
  CUPS ................................... yes
Qt Sql:
  DB2 (IBM) .............................. no
  InterBase .............................. no
  MySql .................................. yes
  OCI (Oracle) ........................... no
  ODBC ................................... yes
  PostgreSQL ............................. yes
  SQLite2 ................................ yes
  SQLite ................................. yes
    Using system provided SQLite ......... no
  TDS (Sybase) ........................... yes
Qt Testlib:
  Tester for item models ................. yes
Qt SerialBus:
  Socket CAN ............................. yes
  Socket CAN FD .......................... yes
QtXmlPatterns:
  XML schema support ..................... yes
Qt QML:
  QML network support .................... yes
  QML debugging and profiling support .... yes
  QML delegate model ..................... yes
Qt Quick:
  Direct3D 12 ............................ no
  AnimatedImage item ..................... yes
  Canvas item ............................ yes
  Support for Qt Quick Designer .......... yes
  Flipable item .......................... yes
  GridView item .......................... yes
  ListView item .......................... yes
  Path support ........................... yes
  PathView item .......................... yes
  Positioner items ....................... yes
  Repeater item .......................... yes
  ShaderEffect item ...................... yes
  Sprite item ............................ yes
Qt Gamepad:
  SDL2 ................................... no
Qt 3D:
  Assimp ................................. yes
  System Assimp .......................... no
  Output Qt3D Job traces ................. no
  Output Qt3D GL traces .................. no
  Use SSE2 instructions .................. no
  Use AVX2 instructions .................. no
  Aspects:
    Render aspect ........................ yes
    Input aspect ......................... yes
    Logic aspect ......................... yes
    Animation aspect ..................... yes
    Extras aspect ........................ yes
Qt 3D Renderers:
  OpenGL Renderer ........................ yes
Qt 3D GeometryLoaders:
  Autodesk FBX ........................... no
Qt Bluetooth:
  BlueZ .................................. yes
  BlueZ Low Energy ....................... yes
  Linux Crypto API ....................... yes
  WinRT Bluetooth API (desktop & UWP) .... no
Qt Sensors:
  sensorfw ............................... no
Qt Quick Controls 2:
  Styles ................................. Default Fusion Imagine Material Universal
Qt Quick Templates 2:
  Hover support .......................... yes
  Multi-touch support .................... yes
Qt Positioning:
  Gypsy GPS Daemon ....................... no
  WinRT Geolocation API .................. no
Qt Location:
  Qt.labs.location experimental QML plugin . yes
  Geoservice plugins:
    OpenStreetMap ........................ yes
    HERE ................................. yes
    Esri ................................. yes
    Mapbox ............................... yes
    MapboxGL ............................. yes
    Itemsoverlay ......................... yes
Qt Multimedia:
  ALSA ................................... yes
  GStreamer 1.0 .......................... no
  GStreamer 0.10 ......................... no
  Video for Linux ........................ yes
  OpenAL ................................. no
  PulseAudio ............................. no
  Resource Policy (libresourceqt5) ....... no
  Windows Audio Services ................. no
  DirectShow ............................. no
  Windows Media Foundation ............... no

Note: Also available for Linux: linux-clang linux-icc

Note: -optimized-tools is not useful in -release mode.

Note: Disabling X11 Accessibility Bridge: D-Bus or AT-SPI is missing.

If nothing looks suspicious here, you are ready to start the build.

9. Run the following to build Qt (took around 9 hours 30 minutes):

$ make -j3 2>&1

Do not launch 4 threads to use all cores with -j4. I observed that this slows everything down due to excessive swap usage.

10. Run the following to install Qt (took around 10 minutes):

$ sudo make install

11. Add the following lines to the end of ~/.bashrc:

export QT_QPA_FONTDIR=/usr/share/fonts/truetype/piboto
export PKG_CONFIG_SYSROOT_DIR=/
export PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/share/pkgconfig:/usr/lib/arm-linux-gnueabihf/pkgconfig
export PATH=/usr/local/qt5/bin/:$PATH

Restart your terminal session. Now, qmake -query should return the below:

QT_SYSROOT:
QT_INSTALL_PREFIX:/usr/local/qt5
QT_INSTALL_ARCHDATA:/usr/local/qt5
QT_INSTALL_DATA:/usr/local/qt5
QT_INSTALL_DOCS:/usr/local/qt5/doc
QT_INSTALL_HEADERS:/usr/local/qt5/include
QT_INSTALL_LIBS:/usr/local/qt5/lib
QT_INSTALL_LIBEXECS:/usr/local/qt5/libexec
QT_INSTALL_BINS:/usr/local/qt5/bin
QT_INSTALL_TESTS:/usr/local/qt5/tests
QT_INSTALL_PLUGINS:/usr/local/qt5/plugins
QT_INSTALL_IMPORTS:/usr/local/qt5/imports
QT_INSTALL_QML:/usr/local/qt5/qml
QT_INSTALL_TRANSLATIONS:/usr/local/qt5/translations
QT_INSTALL_CONFIGURATION:/usr/local/qt5/etc/xdg
QT_INSTALL_EXAMPLES:/usr/local/qt5/examples
QT_INSTALL_DEMOS:/usr/local/qt5/examples
QT_HOST_PREFIX:/usr/local/qt5
QT_HOST_DATA:/usr/local/qt5
QT_HOST_BINS:/usr/local/qt5/bin
QT_HOST_LIBS:/usr/local/qt5/lib
QMAKE_SPEC:linux-g++
QMAKE_XSPEC:devices/linux-rasp-pi3-g++
QMAKE_VERSION:3.1
QT_VERSION:5.11.1

12. Install the usual plugins below, follow the Desktop build for Linux instructions found in their respective README.md's (you can just call qmake at the relevant step instead of providing the whole path):

13. From inside cellulo-qml-plugin, install the cellulorobothubd tool found in tools/cellulorobothubd/ in order to be able to use the RPi as a robot hub that provides connections to more than 5 robots over multiple adapters to platforms that do not support multiple adapters, such as Android, MacOS and Windows. See its README.md for more information on how to install. After installing, reboot the RPi to be able to use it.

14. [Optional] Enable WiFi hotspot functionality in order to connect to the RPi as a hub.

Warning: This method is not recommended for high bandwidth applications, e.g when connected robots are constantly communicating with the app. Use a cabled ethernet connection instead. See below.

14.a. Install DHCP client daemon and the Access Point daemon:

$ sudo apt install dnsmasq hostapd

14.b. Turn them off for now:

$ sudo systemctl stop dnsmasq
$ sudo systemctl stop hostapd

14.c. Add the following to the end of the /etc/dhcpcd.conf file to set up the static IP of the RPi and detach from wpa_supplicant:

interface wlan0
    static ip_address=192.168.4.1/24
    nohook wpa_supplicant

14.d. Restart the DHCP client daemon:

$ sudo service dhcpcd restart

14.e. Save the old dnsmasq configuration:

$ sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.backup

14.f. Create and edit the /etc/dnsmasq.conf file to look like the following:

interface=wlan0
    dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h

This will let DHCP distribute IP's between 192.168.4.2 and 192.168.4.20 to connected clients.

14.g. Configure the Access Point daemon by editing /etc/hostapd/hostapd.conf to look like the following:

interface=wlan0
driver=nl80211
ssid=CelluloRPi
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=cellulo1234
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

Here, we configured our network SSID as CelluloRPi and password as cellulo1234. Feel free to change these as you wish.

14.h. Edit /etc/default/hostapd change the line that says

DAEMON_CONF=""

to

DAEMON_CONF="/etc/hostapd/hostapd.conf"

14.i. Reboot the RPi. When boot is complete, you should be able to connect to its WiFi network and get an IP in the specified range. RPi's own IP will be 192.168.4.1, which is important to know when using it as a hub.

15. [Optional] Enable ethernet access point functionality in order to connect to the RPi as a hub.

15.a. Install the DHCP client daemon:

$ sudo apt install dnsmasq

15.b. Turn it off for now:

$ sudo systemctl stop dnsmasq

15.c. Add the following to the end of the /etc/dhcpcd.conf file to set up the static IP of the RPi:

interface eth0
    static ip_address=192.168.2.1/24

15.d. Restart the DHCP client daemon:

$ sudo service dhcpcd restart

15.e. Save the old dnsmasq configuration:

$ sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.backup

15.f. Create and edit the /etc/dnsmasq.conf file to look like the following:

interface=eth0
    dhcp-range=192.168.2.2,192.168.2.20,255.255.255.0,24h

This will let DHCP distribute IP's between 192.168.2.2 and 192.168.2.20 to connected clients.

15.g. Reboot the RPi. When boot is complete, you should be able to connect to it via a standard ethernet cable and get an IP in the specified range. RPi's own IP will be 192.168.2.1, which is important to know when using it as a hub.

16. [Optional but recommended] If you're going to be using the RPi as a robot hub, disable the internal Bluetooth adapter as its performance seems to be lacking. SSH into the RPi and add the line dtoverlay=pi3-disable-bt at the end of /boot/config.txt. Reboot for the change to take effect. Use external USB dongle adapters for better performance.

Test the hub functionality over WiFi

Warning: This method is not recommended for high bandwidth applications, e.g when connected robots are constantly communicating with the app. Use a cabled ethernet connection instead. See below.

1. Boot your RPi (should take a few seconds only) and connect the desired number of USB Bluetooth adapters. Warning: Connecting directly on the USB ports will place the antennae too close to each other, causing interference (or possibly some kind of coupling). Instead, plug these to your RPi through USB extension cables, making sure that each adapter is farther than a few tens of centimeters with respect to each other.

2. With your desired device that has Cellulo Robot Hub GUI installed (see tools/cellulo-robot-hub-gui/), connect to the CelluloRPi network with the default password cellulo1234 or another that you chose earlier during installation.

3. Launch the Cellulo Robot Hub GUI, select 192.168.4.1 as the server address (or another that you chose earlier during installation), the server port and hit Connect. You may have to wait a few seconds.

4. Scan (done locally on your device, which must have Bluetooth functionality), add robots and connect to them as usual. Close the Cellulo Robot Hub GUI when all desired connections are established.

5. Instantiate the CelluloRobotHubClient with the same serverAddress and port in your app to be able to use these connected robots. See samples/cellulo-robot-pool-hub-demo/ to see how.

Test the hub functionality over ethernet

1. Boot your RPi (should take a few seconds only) and connect the desired number of USB Bluetooth adapters. Warning: Connecting directly on the USB ports will place the antennae too close to each other, causing interference (or possibly some kind of coupling). Instead, plug these to your RPi through USB extension cables, making sure that each adapter is farther than a few tens of centimeters with respect to each other.

2. With your desired device that has Cellulo Robot Hub GUI installed (see tools/cellulo-robot-hub-gui/), connect to RPi's onboard port with a regular straight ethernet cable, DHCP should give you an IP right away.

3. Launch the Cellulo Robot Hub GUI, select 192.168.2.1 as the server address (or another that you chose earlier during installation), the server port and hit Connect. You may have to wait a few seconds.

4. Scan (done locally on your device, which must have Bluetooth functionality), add robots and connect to them as usual. Close the Cellulo Robot Hub GUI when all desired connections are established.

5. Instantiate the CelluloRobotHubClient with the same serverAddress and port in your app to be able to use these connected robots. See samples/cellulo-robot-pool-hub-demo/ to see how.