Boards & sensors
A microcontroller board on a USB cable turns any sensor into a knob and any Humus control into a switch, a dimmer or a colour. There are two ways to talk to one, and this page walks both with an Arduino Uno:
- Board, an organism that needs no code on the board. Flash the standard Firmata sketch once and its pins are yours.
- SerialIn and SerialOut, for a sketch of your own. The sketch prints and reads plain text or bytes, and the two boxes speak whatever the sketch decided: the sketch is the protocol.
What you need
- A board with a USB serial connection. The examples use an Arduino Uno: six analog inputs (A0 to A5) and the on-board LED on pin 13. A Nano, a Leonardo, a Mega, an ESP32 dev board or a Raspberry Pi Pico work the same way, and the Board organism has a preset for each.
- The Arduino IDE, or whichever editor your board uses, to flash it.
- A sensor with an analog output for the first story: a potentiometer is the easiest, a thermistor or an analog temperature sensor is the one in the story. An LED and a 220 ohm resistor for the second story, or just the on-board LED on pin 13. A 24-LED addressable ring for the last three.
Every patch and sketch on this page is under File > Examples > Organisms
in Humus, one folder per scenario: Board holds the two Firmata stories,
SerialIn and SerialOut the sketches of your own, the NeoPixel folder the
ring. The same tree is the examples/ folder of the source, so the sketch
to flash sits next to the patch that drives it, in a folder of its own
name as the board's editor expects.
On Linux the port belongs to the dialout group; add yourself with
sudo usermod -aG dialout $USER and log in again. On macOS and Windows the
port is ready as soon as the board is plugged in. Whichever way you go,
close the IDE's Serial Monitor after flashing: only one program can hold
the port.
No code on the board: Firmata
The Board organism speaks Firmata, an open protocol the Arduino IDE ships a sketch for. You flash it once and never open the IDE again:
- Open the Arduino IDE, plug the board in, pick the board and its port under Tools.
- File ▸ Examples ▸ Firmata ▸ StandardFirmata, then Upload.
Story one: a temperature sensor plays a filter
Wire the sensor's output to A0, its power to 5V (or 3.3V, whichever the sensor wants) and its ground to GND. A potentiometer goes across 5V and GND with its wiper on A0.
In Humus, open Examples > Organisms > Board > Sensor, or build it:
- Add a Board from the Primitives category and pick Arduino Uno / Nano from its presets. Its Port menu says Auto, which is right when one board is plugged in. Its box meter starts flickering a couple of seconds after the patch opens: the board resets when the port opens and then reports.
- Add a Number and draw Board's outlet out1 (A0) onto the Number's socket. The Number now shows the sensor live: warm the sensor, or turn the pot, and watch the value move. This is the number box of the patching tradition, the place you read a control.
- Add a TestGen, a Filter and a SoundOut. Wire TestGen's two outlets into the Filter's two inlets, the Filter into SoundOut.
- Right-click the Filter's Frequency knob, pick Control with ▸ Number ▸ value, and set the range to 200..8000. No cord this time: the reading you are watching now opens the filter as it rises, and the same Number can drive any other knob the same way.
Every parameter in Humus takes a control this way, and every socket takes a control cord. A sensor that reads 0..1 on the outlet is the simplest thing to route; scale it in the route's range, or with a Slider or Math in between when it needs a curve.
Each outlet reads the analog channel set next to it, so a Mega's A8 is one number away, and Outlets sets how many the box shows. Readings arrive every 19 ms by default (Read every).
Story two: the music lights an LED
Leave the on-board LED on pin 13, or wire an LED with a 220 ohm resistor from pin 11 to GND for the dimming half.
Open Examples > Organisms > Board > LED, or build it:
- Add a SoundIn and a Follower; wire SoundIn's outlet into the Follower. Set the Follower's Threshold so its gate opens on each hit of whatever you play into the microphone.
- Add a Board with the Uno preset. Draw the Follower's gate outlet onto Board's socket 1. Socket 1 drives Pin 1, which is 13 in Digital mode: the LED lights on every hit.
- Draw the Follower's env outlet onto socket 2. Socket 2 drives pin 11 in PWM mode, and the second LED breathes with the level.
Anything that carries a control can drive a pin: a Button for a relay, an LFO for a slow fade, a Slider for a hand on a dimmer. Digital mode switches at 0.5; PWM maps 0..1 onto the pin's duty cycle, and only the PWM pins can dim (3, 5, 6, 9, 10 and 11 on the Uno).
Your own sketch: SerialIn and SerialOut
When the board needs to do something StandardFirmata cannot - read a digital sensor over I2C, drive an addressable LED ring, debounce a keypad - write the sketch yourself and talk to Humus in plain text or bytes. No library of ours, no protocol to learn: the sketch is the protocol, and the SerialOut box shows the exact bytes that leave the wire.
HumusBoard.ino is the starter sketch, in the HumusBoard folder under both
SerialIn and SerialOut, and it does both directions: every 30 ms it prints A0 and A1 as one line,
0.512 0.087, and whenever a line arrives it switches pin 13 with the
first number and dims pin 11 with the second. Flash it the same way as
above.
First, the self-test
Before any wiring, prove the link. Flash SerialTest.ino from
Organisms > SerialIn > SerialTest and open the patch beside it. The sketch prints three numbers twenty times a
second: a ramp that climbs from 0 to 1 once a second, whatever it last
heard from Humus, and A0. A SerialIn lands them on three Numbers. The
ramp moving means the board is talking to the port and the baud is right;
the echo following the LFO on SerialOut's first socket means Humus is heard
and the Format matches; the Button on the second socket lights the board's
built-in LED, the one thing to see on the board itself. If the ramp sits
still, check the port and the baud; if only the echo does, check the
Format.
The same two stories, through the sketch
serial-sensor.hum is story one through the sketch: a SerialIn reads
the line the sketch prints, its outlet a lands on a Number, and the
Number's value opens the Filter through a Control-with route. The Port menu
says Auto and the baud is 115200, what the sketch opens. The readout in the
box moves a moment after the patch opens.
serial-led.hum is story two: the Follower's gate outlet on
SerialOut's socket 1 and its env outlet on socket 2, sent as the
default %1 %2\n line thirty times a second; the sketch switches pin 13
and dims pin 11.
Story three: a pixel ring, three ways
The ring shows a protocol of your own. NeoPixel.ino, under
Organisms > SerialOut > NeoPixel, drives a
24-LED addressable ring on pin 6 and reads one command per line, every
number 0..1 except the pixel count: P i r g b paints one pixel, F n r g b lights the first n and darkens the rest, A r g b paints them all, H h s v paints them all by hue, B v sets the brightness. Wire the ring's
data pin to 6, its power to 5V and its ground to GND, flash the sketch, and
open any of the three patches beside it.
paint.hum is the plain one: four Sliders on four SerialOut sockets, the
Format P %1 %2 %3 %4\n, Send on change. The first socket has Scale
23 and Int on, so a 0..1 slider picks a pixel by number; the others are
how much red, green and blue. Move a slider and that pixel follows.
vu-meter.hum computes the whole message from one value. The Follower's
env sits on socket 1 and the Format reads
F %(floor(v1*24+0.5)) %(v1) %(1-v1) 0\n: the level picks how many pixels
light, and the colour runs from green at rest to red at full, thirty lines
a second. This is the message box doing arithmetic, so the sketch stays
dumb.
spectrum.hum is the Pd patch that maps frequency to colour, rebuilt: a
three-band Crossover splits the microphone, a Follower per band reads
its level, and the three env outlets land on three sockets sent as
A %1 %2 %3\n, bass as red, mids as green, highs as blue, on the whole
ring. Move the Crossover's two frequencies to decide what counts as bass
and what as air. Swap the Followers' sources for LFOs and the ring drifts
on its own; put a Slider between a Follower and its socket to tame a band.
Any of the three could also send H %1 1 %2\n with a hue on socket 1 and
a level on socket 2, and the sketch would do the colour wheel.
The two boxes
Humus to board. A SerialOut shows as many value sockets as its
Values field says, two to start with and up to eight, plus a trigger
socket in On trigger mode, and has a Format field. %1 to %8 print
the values, \n ends a line, \t is a tab, \xNN is a raw byte. Each
value has a Scale and an Int switch, so a 0..1 control leaves as
0..255 with two clicks, and a socket with nothing drawn onto it sends the
number typed in its field. Send picks when: Continuous at the rate you
set, On change so a command goes out once, or On trigger when the trigger
socket rises, which turns a Button into a command box.
Several commands in one box. Write one message per line in the Format
field and a Message socket appears: the number on it picks the line, so
a Number or a Slider chooses between home, M %1 and stop, and a Button
on the trigger socket sends the chosen one.
Board to Humus. A SerialIn has up to eight outlets, a to h: the
first number on each line lands on a, the second on b, and so on. A sketch
that prints its own shape gets a Parse template, the mirror of Format:
T=%1;L=%2 reads T=23.5;L=0.4, and a line that does not fit is ignored.
With a template set, a match outlet fires whenever a line fits, so a
sketch that prints pressed becomes a Button press. The readout in the
box shows what arrived. Scale to 0..1 on the board; Humus uses the numbers
as sent.
Computed messages. %(v1*180) prints the result of an expression, in
the Math box's language, and %?(v1>0.5){LED 1} prints its braces only when
the test is true, so a message can change shape with a value. %b(expr)
and %w(expr) send the result as bytes.
What the box shows. Every serial box says at its bottom which port it is on and what it last sent or received, every byte spelled out, and SerialIn marks a line that did not fit its Parse as skipped. When a protocol does not work, that line is where to look. The presets menu on SerialOut and SerialIn holds the usual message shapes to start from.
Names on the wire. A Var is a value with a name. Draw a Var called
temp onto SerialOut's socket 1 and write %n1 %1\n, and the board gets
temp 0.5. The other way, a SerialIn reading temp 23.5 light 0.4 hands
each number to the Var with that name, wherever it sits in the patch, with
no cord at all: Pd's send and receive, with the name riding on the value.
Bytes, not text. A sketch that talks in raw bytes uses %b1 for one
byte and %w1 for a two-byte word in either field. In Format, Scale 255
turns a 0..1 control into a full byte; in Parse, \xAA%b1%w2 waits for the
header byte and takes the next three, resyncing past anything in between.
Checksums, words and lists. %x or %s in a Format adds the XOR or
the sum of the bytes so far, %X and %S the same as two hex digits, and
%[ and %] mark the part they cover, so $%[HUM,%1,%2%]*%X\r\n is a
GPS-style sentence. %{slow,fast,turbo}1 prints one word out of a list
picked by value 1, and reads back as a position from 0 to 1. %c is a count
byte and %b* the counted bytes, for a packet whose length changes; %*
takes or prints every number on a line. A Parse checks the checksum and
drops a line that fails it. The full list is in each box's help.
The port itself. Frame on every box sets parity and stop bits for the rare device that is not 8N1; the baud list runs up to 1000000 and Custom takes any other rate. Reset decides whether opening the port reboots the board the way the board's own editor does; switch it off for a board that should keep running while Humus reconnects.
OSC over serial. A board that speaks OSC wrapped in SLIP, as the Teensy and ESP libraries do, does not need SerialIn at all: enable OSC over serial under Settings ▸ MIDI & OSC and its messages join the OSC control bus, so OSC Learn on any knob maps them. See MIDI & OSC.
Any number of Board, SerialIn and SerialOut boxes can sit on one port: one cable, three formats, three boxes, and each box says what it sends.
When it does not work
- Nothing flickers. Another program holds the port: the Arduino IDE's Serial Monitor, a previous Humus still closing. Press Reconnect on the box, or unplug and replug the board; the boxes reconnect on their own.
- The meter flickers but the outlets sit at zero. The board is not running StandardFirmata. Flash it again, or use SerialIn for a sketch of your own.
- The meter flickers but the readout sits still. The baud does not match what the sketch opens, or the sketch prints a shape the Parse field does not expect. Clear Parse to take every number on the line.
- Readings only reach part of the range. A sensor rarely uses the whole 0..5V. Set the Control-with range to the part it does use, or put a Slider between the outlet and the destination and set its Min and Max.
- The pin will not dim. Not every pin has PWM; move to one that does.
- Linux says permission denied. The
dialoutgroup, above.