Border Tuner - installation report

We just finished the install of “Border Tuner” a new artwork by Rafael Lozano-Hemmer. I thought it might be nice to share some of the code and methods I ended up using to solve the installation’s requirements.

The lights:
18 Syncrolite XL moving head lights needed to be pointed across the MX/US border and had to perform different motion behaviours together. Via a rotary dial participants were able to sweep a group of 3 lights a long an approx. 270˚ motion path.

Thanks to the great work of @elliotwoods and his ofxCeres addon it was relatively simple to convert virtual 3D points in to pan tilt angles and then in to the correct DMX levels needed for each channel.

In the addon I was able to place my virtual lights and place/translate them more or less to match the real world. A surveyor provided use with the UTM data, basically XYZ location data. So we knew exactly where each light was in relation to the others.

The tricky part was to add the correct rotation vector / orientation to the virtual light models. Translation and orientation are bing used by the addon to then calculate the panTilt angles. In my case I pointed all lights to 4 different places in the sky. One was at 0,0,75 meters, which was about the middle of my “stage”. Others points were picked which formed light bridges across the border. We then had multiple people from multiple angles walkie talkie to me if they thought the lights looked aligned and if they thought the lights needed adjustment in pan or tilt.

I adjusted rotationX and rotationZ, which to some extend moved the light beams in to a better position. But these rotation values do not actually translate directly in to pan and tilt. As we know form ofNode and 3D object orientation that by changing one orientation axis the others get effected too. So, the adjustment on those axis value could only be very slight.
Many times, I was switching back and forth between my previously picked places and kept on adjusting the rotationX and rotationZ values. Eventually we found a good mix. But only when the lights stayed in the same tilt angle range as they were calibrated in.

These moving head lights have a pan range of -270 to +270˚ degrees and most of the time a tilt range of -135˚ to +135˚. This means the same point in the sky can be hit with 4 different pan tilt angle combinations. I noticed that I got the best results when I forced the software to only consider positive tilt angles and discard all other panTilt options. Elliot’s code made it very easy to add these limitations.

I have to admit ofxCeres can do so much more and I did not have the time to use it to it’s fullest potential. The add-on actually let’s you calibrate your moving head lights based on previously collected XYZ marker locations. You point each of your lights to those know locations and collect the pan tilt angles. It’s good to point the lights at the same spot using all the possible panTilt pairs.
The result is that the code will place and orient your virtual light correctly.Virtual 3D points will now match your real world points.

The audio:
The artwork has 3 “stations” on in Parque Chamizal, Ciudad Juárez and 3 is Bowie High School, El Paso. Each station has a microphone and a loud speaker. The voices from each station needed to be available for all other stations. When the lights from station A pointed at station B, the audio from station B needed to be heard at station A. The experience had to be one of tuning a radio dial and slowly fading in and out of different radio stations.
In the past I have used @roymacdonald great ofxSoundObject addon which has a matrix mixer option build in.

I had used his addon extensively in the past to take in multiple microphone streams, audio player files and Dante audio network streams. Those could then be mixed together in dynamic ways and out put to a multiple channel sound device or the Dante Virtual Soundcard.
For this piece Roy extended the addon and created ofxSoundObjects-NDI which allows for connection to the ofxNDI addon made by @nariakiiwatani . NDI usually is used for video+audio. But in our case we only needed audio and did not need highest quality either.
This allowed me to write a NDI sender app that mixed the mic input and an audio file and send them out in to the NDI network. Each of the 6 stations had a macOS 10.14 Mac mini running with this sender app. Also a 6 channel NDI matrix receiver app ran on the same machine, mixing all the incoming NDI streams and outputting them to the loudspeaker.
This worked very successfully and was pretty stable. It took a bit of time to find the right approach to reconnect all the apps in case one got restarted. NDI is pretty good at auto reconnecting but it does not work for all cases. So, in some cases apps had to exit themselves and got restarted by a watchdog script.

I learned that each computer should at least have a 10 mbps connection, which meant that our 100 mbps network was plenty fast.

The communication between the main light controller app and the 6 audio stations was done using ofxOSC since I was more familiar with is. ofxNDI’s metadata option could have been used to also send non-audio messages between the computers. Maybe next time :slight_smile:

The internet:
@Caroline_Record and Guillaume Tremblay, my dear colleagues wrote code to allow the light controller app to post its state to the internet. When ever 2 light stations form a bridge we wanted the website to mimic this state. Caroline used ofxLibwebsockets for this feature. We learned that networks can be tricky. In our case Transtelco, a local network company, was kind enough to provide us with a speedy connection between both countries. They gave us a local and a public network. We still had to insure that ofxLibwebsockets did not block our apps incase the network got lost, or the internet became unreachable. For example pinging needed to be done in a thread and socket setup only be done if internet existed.

If you have a chance to drop by, it’s still on until November 24th.

Border Tuner light controller, showing ofxCeres moving head controls.

Border Tuner light controller, showing 3D visualization of an apex behaviour.

NDI sender, NDI Matrix-Receiver and OBS video recorder.


Amazing to see this @stephanschulz. Really glad it worked out.
Also happy+weird to see ofxCvGui screenshot in somebody else’s project (even if you’ve tinted everything red ?by accident?)

Since we worked together, i’ve also added Strucutral Analysis and Inverse Kinematics to ofxCeres, and learnt a bit more about how to get the best results with the solver (we might have not always been getting the absolute best fits before because some of the solver settings weren’t aligned correctly)

would love to learn what those are and can do?

yes the red was an accident. guess for got to ofPopStyle().

Inverse Kinematics is often used when you have:

  1. a serial robot (motorised joints in a chain)
  2. have a target position/orientation for the last point in the chain relative to the first point
  3. want to know the joint values required to achieve that target

(also it’s often used in animation for when you want to animate a character by grabbing and moving their hands rather than moving all the joints in their arm individually)

Strucutral Analysis is for simulating the stress (Force or pressure) on features within a structure. We’re using it for an upcoming installation to help with engineering. The structural analysis part in ofxCeres gives us the specification required for the individual components, and then we can do more detailed design and simulation of each component in a CAD package with finite element modelling (e.g. Fusion 360 with its design and simulation features)


1 Like

Awesome @stephanschulz. A pleasure working with you. Really glad to see that it all worked properly. It is really great that you took the time to make this thorough writeup.

@elliotwoods I was trying to use ofxCeres but could not get it to run in macos, I don’t remember exactly what it was. Although it seems great. I’ll dig a bit more and let you know.

all the best!

hey @roymacdonald !
i haven’t tried it on osx yet. ceres will work on osx, but there might be some strange project settings i made on windows side to get it to work with oF that we’d need to recreate in other project scenarios

it’s incredibly powerful with glm, i’m hoping to document about it soon

great work. thanks for sharing, stephan, very inspiring.

great stuff!

@stephanschulz , interesting project!

I’m trying to get openframeworks running with Dante Virtual Soundcard and I’m hitting some walls. Maybe you had the same experience and know what’s up?

On windows, i need to run Dante is ASIO mode, or the audio thread throws an exception when it can’t access the installed ASIO driver thread. If I run it in WDMmode, i get no errors, but the audio thread does not seem to run. (audioOut is not called.)

On MacOS, we get an error that a system error occurs setting the sample rate for the device.

I’d normally say: “Okay, Openframeworks and Dante don’t want to play along,” but you seem to have got it to! Any pointers for us?


It has been a while since I used Dante and OF together. But we definitely used it for a couple of projects.

Does your setup work without your OF app; using quicktime or any other audio software to receive or send an audio stream?
In macOS system preferences I had to select the Dante devices for in and output, if I remember this correctly.

I will think about it a bit more.

Thanks for your reply!

Yes, it works without OpenFrameworks, I can select dante output channels as default system output and play sounds out to a networked dante amp without issue. It just occurred to me that I’m using Dante Virtual Soundcard, and maybe you 're using Dante Via?