Connecting a Raspberry Pi, iPad, HoloLens, and Magic Leap ML1

I needed a way to connect and communicate between these devices in places with unreliable WiFi.

January 27, 2020

If you've ever used a public WiFi hotspot before you may understand how flaky and unreliable they can be. For a recent project, I needed to wirelessly communicate between devices in an environment where the available WiFi was shaky.

To do this, I setup a Raspberry Pi (which I will abbreviate as rPi) as a WiFi access point. Devices could then connect to the rPi's network, ask it for a list of connected devices, and communicate using the rPi as the middleman.

This solution eliminated our reliance on WiFi networks outside our control. And, it allowed easier communication between devices, as it removed the need for hardcoding IP addresses and fussing with DHCP reservations.

Below are some details on how this was implemented.


Configuring the Raspberry Pi

First, I loaded the Raspberry Pi with Raspbian Buster Lite. I added an empty ssh file in the /boot directory to temporarily enable SSH because it's disabled by default. Then, I connected it to my network via ethernet and enabled SSH permanently. I used a SSH key for authentication instead of a password. I was able to connect to the device without scanning the network for its IP address by addressing it as raspberrypi.local.

If you are building a similar setup and want to connect to WiFi instead of ethernet for the initial setup, add a wpa_supplicant.conf file with your WiFi credentials in the /boot folder. The official Raspberry Pi Headless Setup Guide has more details.

After setting up SSH, I configured the rPi using the built-in configuration tool:

$ sudo raspi-config

This involved changing the default password and updating all of the packages.


Configuring the WiFi Access Point

There are several ways to setup your rPi as a Wifi access point but I prefer using the open source RaspAP tool. Installing this was as simple as running:

$ curl -sL https://install.raspap.com | bash

Then, I was able to configure the access point by logging in to the default IP address, 10.3.141.1. If you are doing a similar setup, you will want to make sure you change the default access point credentials.

At this point, I had a working access point that all of the above devices could connect to. The devices could ping each other on the network, which was a good sign.


Making the rPi Smarter

Every device on the network is preloaded with an application that knows how to access the rPi through the default access point IP address (10.3.141.1). But, these devices know nothing about each other.

To get these devices talking to each other, I needed a way they could query the network. There are many ways to do this, but I opted to create a simple Go web server that runs on the rPi. When a device on the network sends a request to the rPi it will receive a response listing all of the connected devices:

// Devices are returned in the format:
[Expiration Time] [MAC Address] [IP Address] [Hostname] [Client ID]

1580201504 31:a9:d3:20:1f:23 10.3.141.188 macmini 01:38:f9:d3:20:0f:13

This was accomplished using only a few lines of Go:

With this setup, each device can ask for a list of devices on the same network. They can also use the IP address, hostname, and MAC address to differentiate between devices.

It's worth noting that there are probably ways of discovering network devices using libraries on each of the devices. But, to keep things simple, I opted to use the rPi as a "base station" for this logic.

At some point, the rPi will be responsible communicating directly to the connected devices, including telling them when new devices have joined or left the network. This will change the communication style from a "pull" (every device is periodically asking for a list of devices) to a "push" (devices are notified when new devices join or leave). This will remove the need for the battery-powered devices to constantly pull, and shifts that responsibility to the wall-powered rPi.


Communicating Between Devices

Now that we have a closed and reliable network that devices can connect to, the next step is to start communicating.

This project involves several administrators using iPads to control and monitor several AR devices. When an AR device (for example, a HoloLens or Magic Leap ML1) joins the network, the iPads need to display a notification and allow the administrator to configure it individually. After the AR device has been configured it can be queried for an update on the task it's performing.

To accomplish this, I developed an iPad application that queries the network (via the rPi) for connected devices. These devices are presented in a list by name, allowing the administrator to configure each headset individually. When the configuration is entered, the data is sent from the iPad to the IP address associated with the AR device. The AR devices run a simple server that listens for this data and responds with a success or failure.

Below is an example of how this communication can be accomplished with iOS and Swift.

When run, this function would print the same response we saw above:

1580201504 31:a9:d3:20:1f:23 10.3.141.188 macmini 01:38:f9:d3:20:0f:13\n

Communicating directly to the HoloLens and Magic Leap ML1 is accomplished in the same way; except, in their case, they return a response that indicates their progress in the current task. Each AR device runs a web server that can respond to requests.

Overall, this solution solves our WiFi reliability issues and helps the communication process.