I’ve been researching Harold Cohen’s work recently. He was an acclaimed “traditional” painter until discovering computers when he changed track to pursue work made with a floor-roaming, pen-wielding wheeled robot controlled by his AARON software, which seems like his investigation into the mechanics of painting. He made work in this way from the 1960s to his passing in 2016. I enjoy hearing him talk about his work, and there are several videos online to watch, for example from Youtube:
Of course, Cohen used a precision robot to make his work, but I wondered if I could at least start to think about how to use a similar machine. I found a cheap way to at least explore the possibilities, using a pair of BBC Microbit microcontrollers and a compatible wheeled buggy along with a Sharpie pen and a bit sheet of paper.
My idea was to make up some simple instructions for driving the buggy, and have my laptop send those commands to it: keep the buggy side very simple and have any complicated stuff running on the laptop.

The protocol itself included simple instructions like “move forward a bit”, “turn right a bit”, “how far to the obstruction in front of you?”.
I sent the instructions between laptop and buggy using the Microbit’s built-in radio channel and made the buggy light up its display to show me what it thought it was doing.
In this way, I made a very simple drawing… and realised that my robot was, shall we say, “imperfect”. It’s only a basic educational machine, which manifests in how very inexactly it can be controlled. Attempts to make a closed shape resulted in (much more interesting) outlined blobs.
It was also very apparent that to use this for making real work would need acres of space and similarly oversized sheets of paper for my clunky buggy to roll around on!
But it’s interesting, so I coded up an app that would try to draw lines up to any obstruction and then rotate away to a clear space and continue. I found that cardboard walls didn’t reliably trip the “obstruction sensor” (which is based on echo-location like a bat!) so I ran round holding my hands at the edges of the paper to try and make a wall that the robot could detect to stop it driving itself off!
It worked. Sort of. The end result was a drawing on oversized newsprint:

Addendum
For anyone interested in what the code for something like this looks like, here’s where I ended up. It’s unapologetically naive and simple.
The code running on the Microbit plugged into the buggy is python, responding to a simple protocol sent to it over its radio receiver:
from microbit import *
import radio
import neopixel
import utime
RED = (255, 0, 0)
ORANGE = (255, 170, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
radio.on()
np = neopixel.NeoPixel(pin13, 12)
for id in range(0, 7):
np[id] = BLUE
np.show()
def reset_pixels():
for id in range(0, 7):
np[id] = BLACK
np.show()
def forward():
np[3] = GREEN; np[4] = GREEN; np.show()
pin0.write_digital(1)
pin8.write_digital(0)
pin1.write_digital(1)
pin12.write_digital(0)
utime.sleep_ms(150)
pin0.write_digital(0)
pin1.write_digital(0)
reset_pixels()
radio.send("1")
def right():
np[4] = ORANGE; np[5] = ORANGE; np[6] = ORANGE; np.show()
pin0.write_digital(1)
pin8.write_digital(0)
pin1.write_digital(0)
pin12.write_digital(1)
utime.sleep_ms(100)
pin0.write_digital(0)
pin12.write_digital(0)
reset_pixels()
radio.send("1")
def get_distance():
pin15.write_digital(1) # Send 10us Ping pulse
utime.sleep_us(10)
pin15.write_digital(0)
while pin15.read_digital() == 0: # ensure Ping pulse has cleared
pass
start = utime.ticks_us()
while pin15.read_digital() == 1: # wait for Echo pulse to return
pass
end = utime.ticks_us()
echo = end - start
distance_cm = int(0.01715 * echo)
return distance_cm
def sense_distance():
np[3] = RED; np[4] = RED; np.show()
distance_cm = get_distance()
reset_pixels()
scaled_distance = min(int(distance_cm / 20), 5)
radio.send(str(scaled_distance))
sleep(100)
reset_pixels()
while True:
recd = radio.receive()
if recd != None:
if recd == 'm':
forward()
elif recd == 'r':
right()
elif recd == 'd':
sense_distance()
utime.sleep_ms(50)
The Microbit plugged into my laptop relays instructions from its USB connection to the radio channel, again python code:
from microbit import *
import radio
radio.on()
uart.init(baudrate=115200, bits=8, parity=None)
uart.write('\r') # flush junk
sleep(100)
while True:
while not uart.any():
sleep(100)
from_laptop = uart.read(1)
radio.send(from_laptop)
display.scroll(from_laptop)
from_buggy = None
while not from_buggy:
sleep(20)
from_buggy = radio.receive()
uart.write(from_buggy)
And the program that makes the drawing is ruby code running on my laptop that sends instructions to the connected Microbit via USB:
require 'rubygems'
require 'rubyserial'
$serial = Serial.new("/dev/cu.usbmodem102", 115200, 8, :none)
def waitAck
begin
response = $serial.read(1)
sleep(0.05)
end while response.empty?
response
end
def forward
$serial.write("m")
waitAck
end
def right
$serial.write("r")
waitAck
end
def senseDistance
$serial.write("d")
waitAck.to_i
end
def avoid
loop do
right
right
d = senseDistance
break if d > 0
end
end
loop do
d = senseDistance
puts "Distance: #{d}"
avoid if d < 1
[(d/2).to_i, 1].max.times do
forward
end
end