_____ _      ____  _____ ____  ____  _____ ____    ____  ____  ____  _____ ____  ____  _      _      _  _      _____
/  __// \__/|/  _ \/  __//  _ \/  _ \/  __//  _ \  /  __\/  __\/  _ \/  __//  __\/  _ \/ \__/|/ \__/|/ \/ \  /|/  __/
|  \  | |\/||| | //|  \  | | \|| | \||  \  | | \|  |  \/||  \/|| / \|| |  _|  \/|| / \|| |\/||| |\/||| || |\ ||| |  _
|  /_ | |  ||| |_\\|  /_ | |_/|| |_/||  /_ | |_/|  |  __/|    /| \_/|| |_//|    /| |-||| |  ||| |  ||| || | \||| |_//
\____\\_/  \|\____/\____\\____/\____/\____\\____/  \_/   \_/\_\\____/\____\\_/\_\\_/ \|\_/  \|\_/  \|\_/\_/  \|\____\
                                                                                                                                                             

Week 11: Networking & Communications

From Time-of-Flight Sensor to Networked Drawing Machine

This week’s assignment was to build a wired or wireless node with an addressable interface, and to send a message between two projects. I decided to turn my VL53L1X time-of-flight (ToF) sensor into a tiny networked “rangefinder” node that streams distance into Rhino/Grasshopper, where it controls a live drawing.

The long-term goal is to tie this into the Glowmorph lamp and its telescoping piston arms: distance in the world will map to extension of an inner shell, like a soft spatial barometer. For this week I focused on getting a clean, stable data link between the microcontroller and Grasshopper.

XIAO RP2040 dev board with VL53L1X wired

Node Hardware: XIAO RP2040 + VL53L1X

I used my custom XIAO RP2040 dev board from earlier weeks. The VL53L1X ToF sensor is wired to the I²C pins broken out along the bottom header:

The node has one simple job: continuously measure distance and send it over serial as an ASCII message that’s easy to parse on the computer side.

Arduino / RP2040 Code

I used the Pololu VL53L1X library and formatted each reading as a line that looks like D:123 (millimeters):

#include <Wire.h>
#include <VL53L1X.h>

VL53L1X sensor;

void setup() {
  Serial.begin(9600);
  Wire.begin();

  sensor.setTimeout(500);

  if (!sensor.init()) {
    Serial.println("VL53L1X init failed");
    while (1);   // hang if sensor is missing
  }

  sensor.setDistanceMode(VL53L1X::Long);      // better range
  sensor.setMeasurementTimingBudget(50000);   // 50 ms
  sensor.startContinuous(50);                 // ms between readings
}

void loop() {
  int distance = sensor.read();

  if (sensor.timeoutOccurred()) {
    distance = -1;  // mark out-of-range
  }

  Serial.print("D:");
  Serial.println(distance);  // e.g. D:206

  delay(10);
}

Keeping the protocol as plain text (D:<number>) made debugging trivial: I could watch the stream in the Arduino serial monitor and then point Grasshopper at the same port once everything looked stable.

Serial monitor showing D:206 style output

Talking to Rhino with SuperSerial

Firefly is no longer maintained, so in Grasshopper I used the SuperSerial plugin. Once I wrestled with Windows COM-port drama (remembering to close the Arduino Serial Monitor so the port isn’t “already in use”), the setup was:

SuperSerial connected to COM12 in Grasshopper

The Received output of SuperSerial gives me each line as text, e.g. D:82. From there the Grasshopper definition is just string parsing and remapping.

Parsing the Distance String

Core logic on the Grasshopper side:

  1. Split component: split the received text using : as the separator.
  2. Use List Item to grab index 1, which is the numeric part.
  3. Grasshopper automatically converts the text to a number when it feeds into numeric components, but a Number parameter can be used as an explicit cast.
Grasshopper definition using Split and Item to isolate numeric distance

Mapping Distance to Geometry

As a first experiment I mapped distance to the radius and color of a sphere at the origin.

  1. Use Remap to convert sensor range (e.g. 80–400 mm) into a radius domain (e.g. 0.5–6.5 Rhino units).
  2. Feed the remapped value into the R input of a Sphere component.
  3. In parallel, plug the same value into a Gradient (low distance → warm colors, high distance → cool colors).
  4. Use Custom Preview with the gradient output as the material so the sphere’s color and size both respond to distance.
Sphere radius and color driven by ToF distance

Standing close to the sensor swells the sphere and turns it bright orange; stepping back shrinks it into a small blue dot. It’s a very simple mapping, but already feels like a spatial instrument: I’m effectively drawing in Rhino by moving through the physical room.

Toward a Projected Icosahedron

The next step (either for the final project or a later week) is to replace the sphere with an icosahedron or a small quasi-crystalline cluster. The ToF stream can then modulate edge length, rotation, or even “project” the geometry onto the scalar field of the environment—an implicit, data-driven section cut through space.

Mechanical Daydreaming: From Data to Pistons

While this week was mostly about bits and bytes, it’s tightly connected to the mechanical design themes running through the Glowmorph lamp and the Dis-Assembly work:

For now the “actuator” lives inside Rhino, but the plan is to swap the sphere for an actual rotary or linear stage: think lead screws, shaft couplers, recirculating linear bearings, and a servo like the 20 kg metal-gear ANNIMOS unit I’ve been testing. Networking week becomes the bridge between sensing and real mechanical work.

Group Assignment: Talking to Another Project

For the group networking assignment we reused the same simple text protocol so that my distance-sensing node could also talk to a second project. Because all of the data is just D:<number> lines over serial, another board can “listen in”, parse the distance, and drive its own output device (LEDs, motors, etc.). The nice thing is that the protocol is human-readable and doesn’t care whether the other end is Grasshopper, a Python script, or someone else’s microcontroller.

Reflections

Files from This Week

Back to Home