Friday, August 7, 2020

Marble Machines Part 2 - Electric Boogaloo

Wednesday, July 29th, 2020

Welcome back to another post about Marble Machines! I've kind of been hyperfixating on building these things and so far I've found that it's an excellent way to ignore the current turmoil going on in the world at the moment!

Today I'm just going to post some pictures of the work in progress Marble Machine 2, as well as talk about why things are designed the way they are and how it was to build this thing. Then hopefully I'll link a fun YouTube video at the end where you can spend hours watching the finished machine (because I know I'm going to spend hours watching this thing in real life).

These sections aren't really going to be in any particular order so I just hope you enjoy learning all about this new sculpture of mine!
 
View of the mostly finished sculpture
 

The Frame

The sculpture frame was an important thing for this project. Not only would it provide a structural support for all the elements of the track, but it would contain everything within an enclosed space so that it didn't look like garbage (for an example of a poorly looking sculpture, see my last marble machine post here).

I decided it would be cool to build a sort of truss structure linked together with 3D printed parts, using 4 rods of 14 gauge steel wire to hold it together. I hoped that the redundancy of multiple rods would help straighten out the frame, which is why there is 4 rods per segment. The first time I designed the frame parts I actually made the holes a bit too small, so I made sure to update the design accordingly.

I didn't start by building the frame, since I knew it would be a bit difficult to bend the wire within the structure for larger and more complex tracks. Instead, I built the base, mounted the motor, built the lift, and then started constructing the track within that.

In-Progress Marble Machine with Frame
Forgive my workbench I know it's a mess.

If you happen to be interested in these frame parts, you're in luck! I've uploaded the files for free on Thingiverse here! (Just make sure to follow the Creative Commons License or the ghost of copyright will haunt you).

Track Switches

If you remember my other machine, I had a seesaw mechanism to split the incoming marbles into two streams, one for each track. This was a good first attempt, but had several problems. One of the biggest concerns I had was the amount of height lost with the mechanism, and since I wanted a longer track, I needed one that was more 'vertically efficient'.

So I made a first attempt.

A very sad and crappy marble switch
I don't know why I even thought this would work.

Then I actually did some research and binge-watched all the David Morrell YouTube videos I possibly could until I figured out the secret of marble switching. Then I went back to CAD, drafted up a design, and found it worked like a dream.

So then I made two more, for a total of four different tracks for the marbles. My plan were to have the tracks as follows:

Track 1 - Funnels with marble collector
Track 2 - Spirals
Track 3 - Loop!
Track 4 - Long windy track with standing marbles

Top of the lifting mechanism with 3 track switches


Lifting Mechanism

I did an entire post about the lifting mechanism so if you're curious about the design process of that, read it here. I promise I'm not just lazy and don't want to write about it again.

Funnels

I wasn't sure how well a 3D printed marble funnel was going to work, but I decided to include one anyway. I experimented with two different types of funnel profiles, one that was a sort of logarithmic swept curve, and one that was just a funnel in a straight line from the edge to the hole in the middle. I came to the conclusion that the straight profile actually gave a better spin time so that's the one I went with for two of the three.

Overhead of the three funnels


Spiral Track

I wanted one of the tracks to include a spiral or two, so after fiddling around with the patch workspace in CAD I created a template that I hoped would help me bend perfect spirals. After learning how to actually use the template effectively, I managed to create two spirals of varying sizes for the track that actually work pretty well.
 
Large spiral near the top of the sculpture
 

Marble Collector

I figured it would be quite fun to have the funnel track collect four marbles before running them all down the funnel, instead of one at a time. To do this, I spent way too much time thinking about how exactly to balance the tipping arm, drafted something up in CAD, and ended up with a fairly good working design that collects 3-4 marbles before sending them all down the track together.
 
Marble Collector!
 
 
YouTube Video 

There's a whole lot more to this track than I can possibly explain, so I'll leave you with a YouTube video of the sculpture in action! That way you can watch it over and over again similar to how I turn on this sculpture and watch it for hours at a time.
 
 
 
So anyways, thanks for reading and watching that excellent video, I hope you had as much fun as I did! There might possibly be another sculpture in the works but I can neither confirm nor deny :)
 
Keep on making things!
- Will

Friday, July 24, 2020

3D Printing Adventures - The Quest to Lift Marbles (and how Failure is part of Learning)

Wednesday, July 1st, 2020

Today it's me vs. gravity in the ultimate engineering showdown in one of the oldest challenges in the book. My goal is to lift a marble approximately 32cm off the ground. (for those who prefer it in inches, that's 12.5 inches). This is a goal that should be easy, but as is everything in life, it was easier said than done.

First, a Note about Sadness

It's never fun to be sad. But as a reminder to future me (and of course, all of you), if you're ever feeling sad, go outside and do something. I started writing this after getting home from a ride inspired by me just not feeling right, but a little vitamin D cleared my head right up. Turns out demons can't run very fast, and I easily out-ran them! (out-biked? I don't know).

Design Happens in Iterations

This is probably going to be my first blog post covering more than one iteration of a design. And I thought I would go into a little bit about how I design things and why I follow the process that I do. I'll even explain what causes me to abandon a project, and hopefully inspire you to keep working even if you run into points of failure.

I had an initial design for my marble lifter, which was going to require a lot of CAD and 3D printing knowledge that I didn't yet have. And with the motor that I purchased, I was going to not only have to build a lifter, but also something to bring the speed of my motor down to power that lifter. (you can read about my gearbox adventures here).

So I did some research, jumped into CAD, and after several hours and design failures later, I had version four of the first version of my marble lifting device.

Assembled Drive Train of Version 4
This was something that I knew was going to require tweaking, and I honestly doubted that it was even going to work when I started printing it out. Well, many hours and many grams of 3D printing material later, I had brought the design to life.

My next step was to add the steel wires that would guide the marbles and form the support structure. This is where I started to run into issues, like glue not working and how to solder without messing up the gears. The tension on the marbles started to be a bit too much, and the whole thing was just flimsy and could easily fall apart. It was around then that I finally reached a point that I've reached with many other projects before this one.

Every Experience is a Learning Experience

As you start building things, especially for the first time, the experience is mainly there to teach you what doesn't work. This is some advice I've learned over my however many years of building things, and some advice I would love to share with you.

That advice is that every experience is a learning experience. Back when I was just getting started with 3D printing, I was also into a computer game called No Man's Sky. All jokes aside, I loved wandering the depths of space while jamming out to chill music for hours on end. One of the things in the game is called a Multi-Tool, basically your mining-laser, grenade-launcher, and bolt-blaster all in one. What made it cool was that multi-tools were generated differently depending on what star system you were in, so I knew that the chances of coming across someone with my same multi-tool were very, very slim.

One day, maker-me and gamer-me put two and two together. I had to build one of my own in real life. Not an actual mining laser and blaster, but at least a replica of one.

So I started modeling. At the time, it was my most complex CAD model I'd ever built. I spent hours modeling this thing, starting with a real drawing of it and working from there. This thing was going to have all of the bells and whistles, with full RGB LEDs, on/off switches, and a threaded battery compartment (at the time this was amazing to me). I was eager to get printing.

Finished 3D Model
As I printed and assembled the pieces one by one, I started to come across mistake's I'd made during the design and build process. I didn't account for tolerating, which caused some of the pieces to misalign. I hadn't exactly designed it to be strong, which I knew was going to be a problem. And at one final moment when I accidentally forgot to put a resistor between my smaller LEDs and the power supply and fried them all in a brilliant pop, I realized I was way in deep with this project, not knowing if I was going to make it out successfully.

But what I could do, and what I ended up doing, was taking everything that I'd learned over the course of the project and carry it forward, leaving the project itself behind. Because the most important things, more important than any build or physical model, is the lessons learned and the experience gained along the way. To illustrate this point, I'll rely on a quote from one of my family's favorite animated films of all time (see if you can guess which one).

Fun Fact: I blame Meet the Robinsons for making me into an engineer as well
I know many of you will disapprove, since I've admittedly done this on several occasions. A 3D printed wolf head with LED matrix, or this marble lifter that I've made. But I feel that sometimes you get too far into a project, to the point where trying to dig yourself out of a hole of mistakes becomes more of a burden than starting anew with the new knowledge you've gained. I know now to better plan for disassembly, and how to properly tolerance a 3D model. The end result of my adventures might not be beautiful enough to carry around a convention or show off in a public space, but I can look back at them and know that I learned quite a bit putting them together.

By no means am I saying you should quit whenever you encounter a bump. Situations will arise where you make a mistake and should identify what happened and then try to overcome it. In this case, the marble lifting device is simply a piece of a larger project, and making the wrong kind of lifter is a simple bump. But rather than give up on this whole project all together, I've taken a step back, let the ideas ruminate, and sat down and built a better model. I identified what didn't work, why it didn't work, and how I was going to change the design to rectify it. I took the lessons I learned from my failed attempt at a marble lifter and applied them to this design. And while I'm probably going to end up getting rid of most of the other lifter's parts, I'll emerge with a design that works better.

So remember. Sometimes you 3D print tons of stuff and realize that there is no way in heck that you're going to make this align and look good short of printing it again. Identify what didn't work, figure out why it didn't work, and figure out how to make something that does. You'll likely end up with several versions, but it doesn't matter, because experimentation and iteration is just part of being a maker!

Marble Lift Revision 2

So clearly trying to build a lifter combining steel wire and 3D printing in a precise configuration wasn't going to work, at least not with my current set of skills and experience. So I got back to the drawing board, watched some more videos on the subject, and even scoured for designs that had already been made. What I eventually came up with is something I'm actually pretty happy with, and am confident it will have a high rate of success.

Marble Lifter V2
This design works by putting the marbles in a groove on the corner of the build, then lifting it up using a rotating shaft with a helical groove built into it. The marbles are then pushed off the top of the lifter and onto a set of wire tracks, put into the build by the small holes at the top. I plan to have this particular design be hand-cranked instead of motor powered, since I'm not sure I have the right motor or the right skills to make the motor work just yet.

(Yes, this means that sadly, the gearbox isn't going to be the thing driving this project like I had originally intended it to. Oh well, I'm sure it will find use someday).

Marble Lift Revision 3

So after some testing I realized that this clunky frame surrounding the marbles was going to cost me a lot in material and print time, and was overall unnecessary for what I was doing. (Very important, since I'm running low on material and MatterHackers doesn't restock until the end of July). So I opted to design a third iteration, and this time, I knew it was going to work.

Mounting Disc for bottom of lift
This design replaces the marble frame with a disc and some steel wire to create the lifting groove. The helix is also further optimized for 3D printing, since the last one had an overhang that was still too shallow for the printer to print cleanly.

Partially Assembled Lift Screw
Partially Assembled Lift Screw
I also finally gave in and ordered a 9v power supply, on/off toggle switch, and a motor which spins at 11 RPM. I then modeled a hole in the bottom of the lowest screw segment that fit nicely around the motor shaft and allowed it to spin around as needed.

The final result is assembled using 14 and 16 gauge steel wire onto a frame I'll be discussing more in detail on my post about Marble Machine 2.0. This will also be the main lifting mechanism for that machine, and I have a quick sneak peak of the work in progress!

The final working lift

Thanks for reading, and keep making things!
-Will

Friday, July 10, 2020

Marble Machines Part 1 - First Attempt

Sunday, July 5th, 2020

Hello again everyone! today I'm going to cover the build process for my first attempt at a rolling ball sculpture. Then, I'm going to critique my own build, figure out what worked and what didn't work, and plan a little for my next sculpture and what I hope to improve upon.

Inspiration for the Build

When I was younger, yet another one of my fascinations was with these wire rolling ball sculptures. They had one at my local planetarium and children's museum, and I would spend hours just watching the balls make their ways down the various paths built into the sculpture.

Now, this was a time when YouTube was just starting to take off. There were many videos on the internet of different ball sculptures that I would spend lots of time watching, and I always dreamed of having one of my own someday. Though, at the time, I was unfamiliar with where you could go to buy a rolling ball sculpture and didn't yet understand the concept of having to commission someone to build one for you.

So I shelved the idea. It's always been in the back of my head, but I haven't ever made an actual attempt to try to get one.

Fast forward to the year 2020. There's this global pandemic going on, and I finally realized that keeping myself informed wasn't doing wonders for my mental health. So I started to take on more and more projects, hoping that by working on lots of things at once I could distract myself from the fact that society is on fire. It was then I finally came across a fantastic YouTube video with complete instructions on how to build a marble machine with steel wire.

That video is here for those curious. It's a fantastic guide, one that I didn't follow step by step but used for general guidance.

I knew how to solder, and I knew how to bend wire. Maybe the marble machine of my dreams wasn't too far out of reach...

Getting Started and Constructing the Sculpture

After saving up money DoorDashing, I purchased some steel wire. I opted to go for both 16 and 14 gauge wire, intending to use one for the main structure of the machine and the other for the track itself. So I soldered together a mesh grid for the base and added a few support struts before trying to put some track together.

After two or three days of work, I had a very, very simple track. Nothing fancy, but to me it was a good start.

Initial track on the machine
I moved my workspace into the garage, and the next time I sat down to work, I began on trying to build a track switching mechanism. This took me all of two or three hours to solder, because I was more familiar with soldering electronics and not structural wire. The result wasn't the best switcher to ever exist, but I knew it would work well enough.


Marble Divider in Action
I spent the next week or two constructing the rest of the track while I brainstormed how to build a lifting mechanism. As the machine came together, it became less flimsy and more fleshed out, and I was actually pretty happy with how the build was turning out. However, I was running into an issue with the lifting mechanism, and ultimately the problems started stacking up as they usually do. Eventually, I had a sculpture that was 80% done, though there was a conversation between me and my mom that made me realize something.

She asked when it would be done, saying she wanted to display a marble machine around our house somewhere that could run off a motor automatically. Given my previous adventures with gearboxes and lifting mechanisms, I realized that adding a motorized lifter to this sculpture was going to be difficult.

That wasn't my biggest concern though. This thing wasn't enjoyable to look at in the slightest. What I envisioned was a beautiful sculpture with balls and a lifter that would be the centerpiece of a room or make a good talking point in conversation. What I had produced looked like a half-hearted final project for a high school shop class. I wasn't going to proudly display this on my desk in my dorm room, I was probably going to shelf this in my closet with my other experimental projects.

And so I realized this was probably the end for this particular sculpture. But even if I'm not going to display it proudly in a public space, I did learn an awful lot about how to build one, and I feel that with a little bit better planning, I'll be able to create a sculpture 10x better and more fun to look at.

Almost Finished Build on Workbench

Lessons Learned

There's a few things I learned during the build process that I would've loved to know beforehand. I'll be documenting those here just in case you'd like to build your own and don't want to have to learn these things on your own.

1.  Soldering vs. Welding

"Professional" marble sculptures are built using TIG welding, which is probably the most precise of welding processes. This ensures strong connections between wires, and I'm fairly sure steel wire plays better with welded joints rather than soldered connections.

The reason I'm not using TIG welding is because I don't currently have access to the equipment needed. However, I learned that soldering steel wire can cause the wire to heat up and screw up nearby solder joints, which isn't something that occurs with welding. If I build larger sculptures or end up using larger marbles in the future, I'll likely start to use a welder to put the sculpture together. However, for now, soldering should be just fine for what I'm building.

2. Planning is Essential

The biggest lesson I probably learned was about planning. The only planning I did was building a steel mesh to base the sculpture off of, and that was it. This left me a lot of room for experimentation, which is good, but I didn't know what I wanted the end result to look like. It's like knowing your destination is North but not having a map to follow, and in this case, I wasn't really satisfied with the look of the end result.

I've already started planning how I'm going to build my next sculpture, and let me tell you, I think it's going to turn out great. I've given myself dimensional limits, and I've put in space for the lifting mechanism before instead of after, so I know I will be able to fit it.

3. Helping Hands are Excellent

If you intend to do any sort of work on a smaller scale, I recommend you get a set of helping hands. Not a friend or family member, but a small jig that will help hold parts. These can be awesome when it's hard to reach a particular spot, hard to hold still, or if the part you need to hold will burn you if you touch it. I will probably even be getting a second set since they were so helpful on this project.

A Sneak Peak into Future Sculptures

Now that I've learned from my first time building a marble sculpture, I've set a few goals for my next marble machine:

- Machine must be nice to look at
- Machine must be motorized, and powered by wall power
- Machine must have an on/off switch
- Machine must be constrained within a predefined space
- Machine must use a combination of wireworking and 3D printing

The last goal is a stylistic choice. As I've researched different marble machine makers, I'm starting to realize that just like many different kinds of art, each maker has their own unique style. And I've decided that I want to pioneer the combination of 3D printing and wireworking into one marble sculpture. I think this will bring a lot of life and color into the sculpture itself, which should make it look all that much better.

So the next step is to get some new 3D printing filament, and to wait for my low-rpm motor and power supply to show up. Until then, I suppose I can work on some of the 3D models, but you never really know how things are going to turn out until you're holding a physical prototype in your hands. Having this project under my belt, I have high hopes for the next sculpture!

Thank you again for reading, and as always, keep making things!
- Will


Friday, June 26, 2020

3D Printing Adventures - 111:1 Gearbox

Monday, June 22nd, 2020

Hello again! Today I'll be showing off some of my 3D designs for 3D printed gearboxes!

Why are you making Gearboxes?

Well there are a few reasons.

The first is that since I've been staying home a lot, and I've been distracting myself from the current news with building lots of projects. This is, in fact, what inspired my personal quote for 2020.

Feel free to justify you're crazy adventures with this quote :)
Along with this sudden urge to build things came the realization that I finally have some of the skills needed to build things I wish I had when I was younger. In turn I've started getting back to my roots, the childhood fascinations that led me to becoming so interested in engineering in the first place. One of these things was gears.

 *Sidenote, I set off to take a photo of the gear toys I had when I was really little but was unable to find where we kept them in the house. So have a stock image of them from Learning Resources instead. I am surprised that these things are still around and available for purchase. I'm not sponsored, but if you want your child to become as crazy as I am then here is a good place to start.
Gears Gears Gears! (That's the name of the toy if you're interested)
I'm not sure what about gears was so fascinating to me. You spin one, the next one spins, and so on. When I was younger, this was just a fun and interesting concept to think about. But now I am able to realize that you can use bigger and smaller gears to make things spin faster or slower, or with more force. I'm also able to use computer design software, something I couldn't even fathom when I was younger.

The second reason is that I need it for another project I'm working on. I bought a motor that spins way too fast for the project, and I figured why not make a gearbox to slow it down a little. (As a hint, 5000+ RPM is a bit fast for marbles). So not only am I going to build something that I'm likely going to be staring at for hours, but it will also aid me in powering something else I'll likely stare at for hours.

CAD Time

I've tried modeling gears in CAD, and it's not exactly easy if you want to do it correctly. You could just make some teeth out of a trapezoid, then use a rotational pattern to create a gear, but it isn't the best way to go about it. You have to manually do all of the math on the gear sizes, and the teeth won't mesh together well in the end.

Some quick googling led me to discover that Autodesk Fusion, my design software of choice, actually has a built in script for making spur gears (the most basic type of gear). Learning how to use it was a bit of an adventure, but once I figured out the basics, it was time to actually start designing the gearbox.

I didn't exactly set off with an exact gearing ratio I was trying to achieve, I just new I wanted to bring the final speed under 60RPM, or 1 rotation per second. This is 0.012 times the original RPM of 5000 (a totally rough estimate the package said it was somewhere between 5000 and 10000 and I don't have any tools to measure it). I absolutely could've done all of the math required, but because I wanted to get to modeling, I just kind of decided to stack gears together until I had something that worked.

Iteration 1

The first time of many during this project that I realized there's a reason I'm an electrical engineer and not a mechanical engineer was during my first iteration of the project.

Iteration 1 of my gearbox
Yeah it looks kind of fancy, and it was going to achieve a very high gear ratio, but it had many, many problems. The shafts could wiggle loose, the gears were absolutely massive, but the biggest problem I ran into was that when I went to print the frame, it failed.

Failed print
It failed because the support struts snapped in the middle of printing. Why? Because they were 5 millimeters thick. I don't know about you, but 5mm of plastic sort of fused together isn't going to sustain gears spinning at over 5000RPM. Why I even considered this was possible was beyond me, and that's the moment I thought "yeah this is why I chose to study electrical engineering instead of mechanical engineering".

Iteration 2

I decided to learn from my mistakes and make thicker support shafts, smaller gears, and have the whole thing be thicker and more sturdy overall. I also removed the threaded shaft design and instead designed it so that each pair of gears was a single part, with a hole through the middle for a central shaft that threaded onto the gearbox.

Iteration 2 of my gearbox
I was so proud of this design, I thought I'd finally cracked the code of making arguably my most mechanically complex CAD project to date. I quickly exported all of the parts, sliced them, and started the five and a half hour print for the frame. After that, I spent another two hours printing one of the main gears.

I popped the gear off my build plate, and held it in my hand. Then I looked at the frame, and then back to the gear. It was past midnight, and I realized my mistake.

I designed the whole thing backwards.

So no, the motor wouldn't spin and be reduced to 48RPM, the backwords gears meant that if force wasn't an issue, I could potentially be spinning the last gear at well over 500,000RPM. I was trying to lift marbles a few feet, not shoot them into orbit!

Defeated, I went to bed. The failed design haunted my dreams.

Iteration 3

Many say the third time is the charm. I woke up the next morning and opened my laptop, staring the beast in the face, knowing I was going to defeat it this time. I made a copy of the project file instead of starting from scratch, because in reality I just needed to change around which mount would drive the main shaft and which would be the motor mount.

The winner - Iteration 3 - Final gear ratio of roughly 111:1
I was even able to reuse the shafts, main gears, and most of the frame. Delighted with my design, I triple checked I wasn't making any mistakes, and send the new frame to the printer.

This thing took seven and a half hours to print, and unsure that I had enough white filament, I decided to print it in blue. In hindsight, it looks way cooler in blue, and really helps distinguish the different parts of the gearbox. I even printed the drive and motor gears in orange, and the three color print just helps highlight how the different parts fit together to make this thing work.

I tested my gear, and it fit perfectly. Satisfied this was going to work, I began printing all of parts I needed for the final assembly.

Bringing it into the real world

It took quite a while to print everything, but behold, the physical rendition of my final design with working motor:

They spin fast and it's loud as heck
This thing is gorgeous. It's nice to look at a theoretical design in CAD and think "yeah, I designed that," but bringing something into the real world and being able to hold what you built is just something else entirely. Having a tangible part that previously existed as merely a bunch of mathematical code and a spool of colored plastic is one of the coolest feelings ever. It's one of those things that make me joyful to live in the 21st century.

So there you have it, my adventures in designing a gearbox for use with a future project! The next step will be getting it working with some of my other stuff, and I'll be covering that in a future post.

Thank you so much for reading, and keep on making things!
-Will

Friday, June 12, 2020

Java Lighting Control Part 3 - The Art-Net Backbone

Thursday, May 21st, 2020

Welcome back! Today I'm going to be discussing the long awaited Art-Net backbone, an essential piece of processing for my Java projects involving stage lighting. I'll be taking a look at how it functions, the different data types and what they do, and how it all fits together to push lighting data to Art-Net.

External Libraries

Since I am not experienced enough to be writing my own Art-Net communication library from scratch, I'm building upon Artnet4J, a library written by Cansik (GitHub page here). This library is the final interface between Java and Art-Net, and what is doing the heavy lifting in terms of communicating with my lights.

What is Art-Net?

Art-Net is a protocol for sending DMX data over IP networking. An Art-Net network is built up of standard IP infrastructure like routers and switches, along with nodes, which are responsible for actually turning the Art-Net data into DMX that the lights can interpret. The Art-Net node I am using is an ELC DMXLan Buddy, which is capable of outputting 2 universes independently (a universe being a chain of 512 DMX channels).

<Photo of DMXLan Buddy>

The reason I am using Art-Net rather than something like USB to DMX conversion is because Art-Net is easier to support, since you don't have to worry about compatibility with all different USB to DMX dongles. With Art-Net, all you have to do is specify an IP address and universe, and any node that supports it will be able to read and convert the data.

Using Artnet4J

The basic thing to understand about Artnet4j is how data is packaged before being sent to Art-Net. The data takes the form of an array of 512 bytes containing values between 0 and 255. Each index position specifies a DMX channel, and each value is the value that gets pushed to that channel. From there all you have to do is create a client to handle the communications side of things, and push the array to an IP address and universe.

This is a very easy library to use, but because the software I am building is going to be relatively complex, I needed to build upon it to make things as solid as possible for use in the future. This includes creating objects for each universe to save things like IP address and universe ID, and defining different data objects for my software to work with.

Data Types

There are four main data types that my software is able to use, which are commands, frames, scenes, and stacks. These are essentially containers for each other, and the way they are encapsulated in the following way: each frame contains several commands, each scene contains several frames, and each stack contains several scenes. While I haven't yet created a project that utilizes scenes or stacks, every experiment with Art-Net in Java has extensively utilized frames.

Commands are simple, lightweight data types containing an address, universe, and data value. In essence, it is there to say "this channel at this value on this universe". By itself it simply controls a single light, but when there are many commands encapsulated in a single frame, things become more interesting.

Frames are what are actually sent to Art-Net, since they contain an array of commands which need to be read and sent out to each universe. The cool thing here is that frames are not universe specific, so you can control any lights in any universe together in a single frame.

One more step up the chain, we see that each scene contains a series of frames, much like a video contains a whole bunch of still images that it combines to create the illusion of video. This is going to be important in future projects where I need to worry about different scenes stepping through commands in sequential order, but for now it's just there for future implementation.

Finally, there is what is called a stack, which is a bunch of scenes meant to play side-by-side with each other. Once again, this is here for future implementation and isn't utilized currently.

Universes

The next thing I needed to do was to create an ArtnetUniverse object so I can reference each universe independently without worrying about specifying an IP address each time. I also store a Universe ID,  which is a unique identifier that my software can use to figure out which universe to send data to. The class also contains methods for writing data to the universe, and also for sending the universe data out to Art-Net.

Art-Net Router

The Art-Net router is an object that takes data and routes it to each universe, depending on the desired universe ID. When sending data to Art-Net, the data is encapsulated in a frame, and a router 'opens' a frame, reads each command, and sends it to the correct universe depending on the universe address in the command. This is essentially the link between the Art-Net part of Java and the rest of a program, as it serves as a hub for routing commands. However, unlike IP routers in the real world, this is merely an object in a Java program and not a physical router.

Putting it all Together

The last step is to combine all of these steps into a final project. For sake of example, I'll be explaining how I use this in my last project, the simple dimmer and color controller (see that project here).

First is to create and initialize all of the objects we need for Art-Net to work.
Initialization code
The first few lines create and start the Art-Net client on my machine, which is what will talk to all of the nodes over the network. Next, I create the router object. Then, I create two universe objects for each universe on my DMXLan buddy, which currently has the statically assigned IP address of 192.168.1.63 on my small, 2 device Art-Net network. Finally, I add references to both universes to the Art-Net router, and now the code is ready to send Art-Net.

The next step is to create a frame object. We only need one since this is a basic controller and isn't working with saved scenes and frames.
Creating and assigning the frames to the fader banks
This is a simple code to create a frame and assign it to the faders through use of the fader banks, which are explained in my last post.

Next is the code to write data to each frame. This is a simple method call for the frame object.
Code for adding a command to a frame
This code creates a command within the frame. In the context of the router, the channel is what channel the command is for, the DMXint is the data that is being sent to that channel, and the universe is what universe the command is supposed to go to. This is done within each fader when it receives a MIDI command from the Launchpads.

The last step is to send the frame to the router, which is done each cycle through the main loop.
Commands for sending Art-Net data
The first two lines send the DMX data from each fader bank to the active frame using the method we discussed above. The next line pushes the frame to the router, which sends it to each universe's data array. Finally, the last line pushes the data from each universe out to the specified node, and then to the lights.

And there you have it! This is the Art-Net framework I will be using in future projects since it offers simple functionality that builds upon existing Java Art-Net libraries. Thanks to Cansik for making the library exist so I don't have to start from scratch!

That's all for now, thanks for reading! Keep on making things!
-Will

Tuesday, May 19, 2020

Java Lighting Control Part 2 - Building a Simple Color and Brightness Controller

Monday, May 17th

In my previous post (available here), I explored integration of both of my Launchpads into Java. At the end, I teased a basic control project with both pads and explained I'd be posting about it. So here I am with the full project build process explained as best as I can.

The Goal

This is more of a first step in the ultimate goal of lighting control, rather than a functional project that I can actually use during gigs. My goal is to control up to 8 lights using both launchpads, one Launchpad to control the brightness and one to control the color.

Planning - Control Flow

The first thing I usually do when starting a Java project is draft the flow of data through the project so I can get an idea of what I'm trying to accomplish and what objects I will need to create. This usually takes the form of a whiteboard sketch.

From my initial brainstorming, I came up with the basics of what modules I need to build and how they communicate with each part of the program. I will need a way to create lighting fixture objects to store how many channels they have, what Art-Net universe they are on, and what their DMX address is. Then, I will need a fader class to act as a controller and middleman between the Launchpads and the lights. Finally, I will need to be able to store colors as both an RGB value for pushing to the lights and as a velocity value to push to the Launchpad.

As for the flow of data through the program, I ended up with two different control paths that I could use. The main difference between the two is how they handle pushing data to the lights.

First control flow idea
The first solution integrates everything I was talking about above, though the lines are a bit hard to follow. Let's start with the left of the program and work our way towards the right.

On the far left in pink are my two Launchpads, MIDI 1 being the MK2 and MIDI 2 being the S. Each push out data to one of two banks of faders, which are drawn in green. One bank of faders are single parameter control faders, which receive data from the Launchpad S and push back MIDI data to light up the Launchpad in a way that reflects the current state of the fader.

The second bank of faders, labeled '3fad', are responsible for holding the Red, Green, Blue, and White channels of the light they're assigned to. (To be fair, that's 4 parameters, it should be labeled '4fad'). This fader needs to be slightly more advanced so it can push RGBW commands to set the color of the light, as well as push color data back to the Launchpad MK2 display. The way it will do this is with the Color object I was talking about earlier that stores RGB(W) values alongside the velocity value for display on the launchpad.

In this solution, data from the faders is pushed to an array in each lighting object that stores the current value of each channel on that particular light. When it comes time to push that data over Art-Net, an object called a frame constructor puts together a list of commands for each channel on each light and pushes it to the Art-Net backbone of my program.

The Art-Net backbone is complex enough for it's own post (here when done), but for now it's important to explain the different types of data that it uses. The first is a DMXCommand, which is simply stores a channel, data value, and universe. The second is a DMXFrame, which is a collection of DMXCommands.

This was the first solution I came up with, but I realized that as more lights get added to the program it would start to take longer to update the universe since I would be generating new data based of the current state of the lights, even if nothing changed. This prompted me to generate a second solution that would be a bit more efficient at scale.

Second control flow idea
 Despite looking wildly different, there's actually a lot of similarities to the first solution here. MIDI input is handled exactly the same, and output to Art-Net is handled the same. The difference is that the faders send data both to the light objects and to the frame constructor, so that instead of rendering all channels all the time, the frame only contains changes that were made. The data is still stored to the lighting objects, however, just in case I need to get the current state of any given light in the future.

This should save vastly on processing time for larger projects, and even though the current project is a bit small, I feel it will be good to start building things efficiently the first time.

Coding Time

Fader Objects and MIDI Integration

I'll start by building the fader classes and setting up communication with MIDI devices. Upon starting this I realized I haven't implemented output for the Launchpad S or Launchpad MK2 classes, so I'll do a quick refresher of how I did that.

Turns out that translation from coordinates to values in the Launchpad S handler is actually super easy. I started by storing each row array into another array list. Now any time that I need to find a pitch value, I use the first value to find the row, and then the second value to find the number within that row.
I've also started commenting my code so it should be clearer
This is the whole code to go from a set of coordinates to a MIDI value with the Launchpad S. But it's clearly way more efficient than trying to go from a MIDI value to a set of coordinates.

Once you have the MIDI note value, all that's left is to output it to the Launchpad. This is handled super easily by one line, which takes a channel (always 0 in this case), pitch, and velocity and pushes it as a MIDI message to the desired bus.
Command to output a MIDI message to the desired bus
As you can imagine, the code for the Launchpad MK2 is a lot better since the MIDI notes are already a concatenation of the row and column.

The next step is to start writing the fader base class, which will be inherited by every different type of fader we will be creating. The base class stores the reference to the particular MIDI Handler we're using, the resolution of the fader, and the column of the launchpad which will serve as the control interface and display for the fader.

Once the base class was finished, I moved onto writing a single-parameter fader class. In addition to inheriting all the base functionality of the base class, this integrates functions for displaying the current state of the fader to the Launchpad in a pre-set velocity color, and updating the display and fader according to input from the MIDI bus.

The way I handle display is by creating an array called display which stores the state of each pixel in the form of a 1 for on, or 0 for off, with the index position representing the Y value of the pixel. The class also includes methods for displaying the data in that array, clearing that array, and updating it according to MIDI input.

In any given frame (representing one cycle of the program), the fader reaches to the MIDI bus it was assigned to when it was created to get the coordinates of the latest note pressed. If the column of the fader aligns with the X value of the data, then it clears the display and turns on any pixels at or beneath the Y value from the data. Finally, it checks through the display array and sends appropriate data to the Launchpad.

The best part is I wrote it in such a way where you can create as many faders as you want by specifying different column IDs. To demonstrate this, I created 8 faders and assigned each to a different column on the launchpad. The result looked something like this:

Faders in operation on the Launchpad S
 As you can see, you can control each fader by tapping on the corresponding button in any given column, and the display reacts accordingly. On the lighting control side, the higher a bar is, the brighter the light is going to be. Even though I haven't implemented Art-Net control to each fader quite yet, this is still a major milestone in actually using MIDI to control the program.

The next step is to write a 4-channel fader for controlling the color of each light. Thankfully, I have some experience now with writing the single-channel fader, however there's still work that needs to go into making this one. Instead of being one color, each pixel on the display has to be a different color, and rather than updating and changing the height of a bar, it simply needs to turn the pixel green when it is pressed to show that it's the current active color on that fader.

The way I plan to implement this is by creating a type of object called a LaunchColor. This stores a velocity value for use with a Launchpad, as well as Red, Green, Blue, and White values for use with Art-Net. I'll then create eight different displayable colors that I can reference and use with this particular fader.

The fader has two arrays, one is for the MIDI display and is purely for showing which color is in each slot. This array needs to be able to change to update the state of the display, which includes which color is active. However, because we also need an array to fall back on when we change the active color, and to continue sending up-to-date Art-Net data. For this reason, I will also be creating a default display array which is just to store what each slot is assigned to functionally.

There is also a method to set a pad color, which simply puts a color in the desired slot. This is so we can set what color is assigned to what pad, and change it if needed. Additionally, the updateDisplay and showDisplay methods are almost identical to the single fader, but output the display color and update the active display color instead of changing the pixels that are lit up.

Once I finished, I realized that running a test with 8 faders would require almost 20 lines of setup per fader. I decided to write a FaderBank class for each type of fader to store references to all my faders. This allows me to create all 8 4-channel faders at the same time, and also allows me to update and show each fader by calling the bank instead of calling each separately. I don't know what the impact on efficiency is, but it at least allows me to save time by not having to write as much code.

After that was done, I finally had my faders built, and it was time to build the actual lighting control side of things.
Finished Color and Brightness Faders
Lighting Fixture Objects and a Primer on DMX

The first thing to do is to create a lighting fixture class to hold data like the number of channels, current channel states, default channel states, and DMX starting address. Therefore, I can create a lighting fixture object for each light in my setup.

I'm sure you're wondering what all this actually is, so allow me to give you a quick primer in the ways of DMX.

DMX (Digital MultipleXing) is a common protocol used for controlling stage lights. It's capable of controlling 512 channels with values between 0 and 255 on a single line. This means that you can daisy-chain lights together with DMX, and as long as the total number of channels is less than or equal to 512, you can control each channel individually.

I have several different kinds of lights, though for this project I'll be using a couple of XPC Pars, which are cheap lights I bought in a bundle on Amazon (link here. They're good lights for what they are but bear in mind, you get what you pay for). Each light has 8 channels (dimmer, strobe, macro 1, macro 2, red, green, blue, and white) which means the total number of lights I can put up to 64 of these on a single DMX chain and still be able to control all 8 channels individually for each light. Light 1 would be address 1 on a chain, light 2 is address 9, light 3 is address 17, etc because each light covers it's starting address and as many channel addresses as it has channels.

The way I control my DMX lights using Java is with a protocol called Art-Net, which I've mentioned previously. Art-Net is a protocol that allows for lighting control using IP networking, which allows for more than 30,000 universes (sets of 512 channels) can be controlled individually. I'll go into more detail about how I implement this into my programs when I cover the Art-Net backbone, but for now just know that I control lights by pushing data to a DMX chain using Art-Net.

DMXCommands from Faders

Referring back to the control flow at the beginning of the project, each fader has to store the channel that it's going to be controlling, and output a value associated with that channel to Art-Net. In the case of the quad-channel fader, it has to be able to output data to 4 different channels at once. These come in the form of DMXCommands, a simple message that basically says "Set this channel to this value on this universe".

On the single-channel fader side of things, all I have to do is assign a light, channel, and universe to each fader so it knows what to control. Then I have to program a way for the MIDI commands to generate data to push to that channel and universe. In this case, the brightness should slowly increase as the Y value of the fader increases.

The good news is that I have a way to get the total Y value of the fader, and that's by adding up the value of all the integers in the display array. Being the math nerd that I am, I decided to hop on over to desmos.com/calculator, one of the greatest free resources on the whole of the internet to see if I could figure out what that equation is.

Graph depicting relationship of brightness to button pressed
I started by graphing 2 points to represent button 1 being 0 brightness and button 8 being full brightness (255). The equation for this line is y = 36x - 36. This means that the value output needs to be 36 less than 36 times the number of the button pressed. However, since Art-Net and DMX really don't like decimal numbers, we have to make sure we cast the result as a whole integer.

From there all we have to do is calculate what channel on the universe this data will be going to since we assign the channel to the fader using the channel per fixture, rather than per universe. This is mainly to keep my head straight, and it's a simple calculation to figure out which channel on the universe we are trying to control.

Calculation of channel in universe relative to channel in fixture.
And there you go, that's how you use math to control lights. After we have that information we just write a method to output the result of our above equation to the channel we get in the lower equation in the universe we get from the fixture that was defined on that fader.

Code for sending DMX data based on the Y value of the single fader
That's all for the single fader, and the quad fader doesn't have to do nearly as much math. However, it does have to output a series of commands for the Red, Green, Blue, and White channels of the fixture it's controlling. This is going to be much easier since we have an array full of colors already that we can pull the RGBW values from.

Code for sending DMX data based on active color of the 4-channel fader
All that's left is to find somewhere to push this data to, and that's where the Frame Constructor comes into play.

DMXFrame Constructor

The frame constructor is the final link between the faders and the Art-Net output. The first step of making this work is creating references to an active frame in both types of faders. Then we create an empty DMXFrame object and add it to all of the faders in our banks so that when the faders output data, it goes to that frame.

Finally, the frame is pushed to a newly created ArtnetRouter, an object that is part of the Art-Net backbone for this program and I will discuss in detail in my post about it. From there it's pushed to my Art-Net node and then out to my lights on the DMX chains!

The Finished Project

After adding all of the object creation to the main function of the program, the program should be fully operational! And there you have it! A simple color and brightness controller for up to 8 different lights written entirely in Java utilizing both Launchpads! This project took me two days to get working, but I think it's an excellent first step in my journey to create my own lighting control application.
Final project demonstration - brightness inconsistency due to phone camera being bad
Thanks for reading this far! I hope you enjoyed! Keep on making things!
-Will

Sunday, May 17, 2020

Java Lighting Control Part 1 - Dual Launchpad Integration

Sunday, May 16th

I told you I'd have a post soon on my Java Lighting Control project so here I am. So far I've built the Art-Net backbone of the program, and so I decided that today's project was to implement MIDI support for both of my launchpads.

Quick primer - what is MIDI and why do I need it?

MIDI stands for Musical Instrument Digital Interface, and it's a technology that's been around for quite a while and something I am all to familiar with. It's basically a communication protocol that allows for MIDI devices to send channel, velocity, and pitch data from something like a MIDI keyboard to a computer based synthesizer without the keyboard itself doing the sound synthesis.

The reason I'm using MIDI as my control interface is because it will allow me to control the application with a pair of Launchpads. If you've spent any amount of time looking at electronic music covers on YouTube I can almost guarantee you've seen one of these before.

A launchpad outputs MIDI messages which I can read using a handy library I found for Java called TheMidiBus (available here for those who are curious). I settled on this Java library because it's nice and lightweight, and I couldn't get the default Java library working after three days of struggle. It doesn't offer nearly as many features as the default Java library, but in all honesty the added complexity of channels, tracks, and sequencers made the signal flow of the project a nightmare. This was the perfect solution.

There are two components of a MIDI message that I'm focused on in this project, which are the pitch and the velocity. On the input side, I'm only focused on the pitch since it tells me which button on the launchpad was pressed. However, in order to make the launchpad light up you have to send MIDI data back. The pitch tells the launchpad which button to light up, and the velocity tells it what color to light up.

It's a bit annoying not being able to use standard LED coloring with RGB values, but the easy solution to this problem is to write an object in Java that stores an RGB value for on-screen display alongside a velocity value to send to the Launchpad. That way I can read a color value to both the application and the launchpad, and both will have data to tell it what color it needs to use.

I've worked with MIDI before in various projects so this isn't my first time working with it. For example, I used Python to write a version of Pong that was controlled and outputted to my Launchpad MK2 (the code is available here for those who want to try it out for themselves. Though it only works for Launchpad MK2). Together with my friend Caden (who is a vastly better Java developer than I am), we wrote a version of this in Java to get the basics of MIDI input and output down. That code isn't publicly available yet but I imagine it will be at some point.

LaunchPong in Python
So I have figured out MIDI input with one device, however, with the way I'm building this control software I want to be able to run two Launchpads side by side to control various aspects of the lighting rig. So that was today's project.

My two Launchpads
On the left is my Launchpad MK2, the new guy on the block and the one featured in the above gif. I purchased it for reasons I will explain later, but it's gotten to see two gigs of lighting control before I ran out of gigs to DJ at. On the right is my Launchpad S, which I bought from a friend when I was first getting into music production. It's been running lights for almost the entire time I've had lights, and has been quite faithful, although it did have a problem.

The problem with the Launchpad S

The main problem I faced with the Launchpad S was due to the way that MIDI channels work. MIDI supports up to 16 different channels of data, which is important when you have, for example, several devices controlling different things. Whenever I would do DJ gigs, I would have two MIDI devices plugged into my laptop at any given time. The first was the Launchpad, which controlled lights via MIDI commands in a program called QLab (full post on this someday). The other was my DDJ-400, a DJ controller that ran Rekordbox, my DJing program of choice.

Both these devices work on the same MIDI channel (which defaults to channel 1 I believe). And while Rekordbox was good at making sure that the incoming data from the Launchpad didn't accidentally pause the music during a gig, QLab just took any MIDI commands that came in on the specified channel and controlled the lights regardless of what device the command had come from. I found myself accidentally turning all the lights green when I pushed play, or turning on strobe whenever I touched my EQ, which was not great. The worst part is, I was completely oblivious to this until I was DJing my Senior prom, and I was fortunate to have Caden as my lighting engineer for the night to correct my mistakes when I was DJing.

The solution was quite simple, all I had to do was change the MIDI channel that QLab was reading and the channel that the Launchpad was outputting. The problem was that Launchpad S is basically diet Launchpad, and while it allows you to change which device ID the Launchpad is (something that Ableton uses for distinguishing which device is which), it does not allow you to configure the MIDI channel. This is when I decided to purchase the Launchpad MK2 as my primary lighting controller since it allows the configuration of which MIDI channel it's outputting on.

This is actually one issue that I actually don't have to worry about in Java. When creating MIDI Bus objects using TheMidiBus library, you actually have to specify sending and receiving devices for that particular bus. Therefore I don't have to muck about with channels, I just have to make sure the correct devices are selected when setting them up.

The other problem with the Launchpad S

Most of my code for this test project was copied and pasted over from the LaunchPong Java project, which was written for the Launchpad MK2. I figured that the control mapping was the exact same on both devices, but I was dead wrong.


Control Mappings for Launchpad MK2
Above is a labeled diagram showing the pitch for each button. Starting in the bottom left with 11 and working up to 88 in the top right. This is really easy on me as far as control schemes go, because to get the X and Y coordinates of the button that was pressed, I just have to split the incoming pitch apart into row and column values. For example, a value of 36 would be row 3, column 6, or (6,3) in traditional Cartesian coordinates.


So I wrote a quick test project to implement both Launchpads controlling at once, and I discovered that I had a huge problem.

Control Mappings for Launchpad S
As you can see, the top left note is 0, and then they increment up by 1 until they reach note 8 at the end of the row. However, instead of continuing to increment up by 1 starting on the second row, it starts over at 16 and continues to do so. The next row starts at 32, and so on. In no way shape or form does it emulate the wonderful note mapping that is present on the MK2.

This is a slightly trickier problem to solve, since my code is written to process things in terms of X and Y values. This doesn't play nicely with the fact that the MK2 and the S have completely different numbering schemes.

The best way to explain this is to go over how my code works. If you're familiar with Java you're welcome to criticize me (please go easy I'm still learning). If you don't know how programming works, Don't be alarmed! I'll do my best to explain so it makes sense.

My first idea was to write a MIDIHandler class for the Launchpad, which would hold functions such as doing something when it received MIDI input, and translating the note that came in to X and Y coordinates for use in the program later. This was a complex beast of code, and since I'm not sure how to paste code into Blogger's editor I'm just going to share screenshots.

The class constructor and MIDI Listener
Methods for translating from data to coordinates and vice versa
The first screenshot shows the class constructor and the MIDI Listener. The first line creates a new MidiBus with the input and output devices that I specify (in our case the Launchpad MK2). The note pressed simply stores the pitch of the last note pressed. The listener is exactly what it sounds like, it simply listens for any input data and when it receives some, it executes the code in the brackets which is to record the pitch of the message that just came in.

The lowest code block on the top screenshot is the constructor, a set of code that's always executed when a new object is created of this particular type. In this case, it just assigns the created listener to the bus specified in the class so the listener knows to listen on that bus.

The lower screenshot uses Java magic to convert a single MIDI pitch into two separate numbers, and the other combines two numbers into one. I'll be honest, Caden wrote these so I'm not fully sure how they work. I just know that they do work and that's all that matters.

So it was here I discovered that copying my previous class from my last project wasn't going to be a good solution. It was here that I decided I needed to add a generous amount of Object Oriented Programming magic.

My idea was to take most of the functionality from this class and make a base class out of it that I can extend to the different types of Launchpad. If you aren't sure what I'm talking about, imagine that the Launchpad MK2 is an eagle and the Launchpad S is a hummingbird. Both are birds and perform bird-like actions such as eating and flying, however the Eagle lets out a majestic screech while a hummingbird hums? (I'll be honest I don't know what sound a hummingbird makes). The idea is to make an object that handles all the things a bird might need to do, and then to create objects that inherit those things from the bird, but also modify or introduce their own functionality depending on what type of bird they are.

Translating this into programming, I have to create a base object for actions that all MIDI devices will need like using a listener, outputting MIDI messages, and things like that. Then, I need to create separate objects for the Launchpad MK2 and Launchpad S since they handle MIDI data differently. I know for sure that more work is going to go into the Launchpad S class since it has to handle translating seemingly arbitrary numbers into X and Y coordinates.

There are several ways I could've done this, but I ended up using an array approach and a whole bunch of if statements (If statements are simple code logic blocks, which see if something is true and if it is, does a thing), along with pre-defined arrays for each row on the Launchpad S.

Forgive my horrible use of white space, it's mainly for making the explanation clearer
The easiest explanation for these is that each array represents a row on the Launchpad (indexed with bottom being 1 so it's like the Launchpad MK2) and each spot in that array represents what column it is. For example, note 17 is row 7, column 2, or (2,7). I know computers start counting at 0 but because Launchpads start at 1, I will be 1-indexing in the MIDIHandler class (I will be 0-indexing everywhere else though).

Prepare for Spaghetti, and make it double
Calling this method will return an array containing the row in the 1st position and the column in the 2nd position. The way it accomplishes this is by checking if the note is within a specific range, and if it is, it runs through the row to see if the note is inside and if it is, it returns what slot it's in +1, since I'm starting my Cartesian coordinates at (1,1).

Is this the best solution? Absolutely not. Is it the solution I know how to program? Yes, it is. I'm sorry for subjecting your eyes to such madness, but I promise it works.

Thankfully, the method inside Launchpad MK2's handler is much more graceful.

This is the whole thing

Basically, when you ask for an array of coordinates from the Launchpad MK2, it simply converts the note into a string, grabs the first and second characters of the string and turns them back into notes, and then returns an array with those numbers as row and column coordinates. Super easy, not painful at all. This version of note to coordinate translation is my own method, because I wanted to prove I am capable of writing one.

After some testing, I've proven this successful, and I'll call it good for my MIDIHandlers for the Launchpad MK2 and the Launchpad S as far as note to coordinate translation is concerned!

The final problem with the Launchpad S

This one is more of a complaint about the design choice and how it is going to be limiting in terms of functionality. Remember when I called my Launchpad S the diet Launchpad? Well for whatever reason Novation decided not to include a blue LED in the Launchpad S's pads, so they're limited on the color range they can show to shades of green, orange, red, and yellow. This is way more limited than the Launchpad S's full RGB pads, which can show 127 different colors depending on what velocity value is passed.

This isn't a deal breaker for an initial test prototype, but it is annoying since I will absolutely be utilizing the full RGB capabilities of the Launchpad when it comes time to start putting together a more refined version of the software.

Final test project

So with all of this knowledge and work that I've done, I wanted to build a basic color and dimmer control for Art-Net output using both launchpads. The Launchpad MK2 will be taking on the job of setting the color for one of four lights, and the Launchpad S will take on the job of being the brightness control. It's not a super fancy application but it's simple enough to demonstrate proof-of-concept for MIDI to Art-Net out. Because the whole program is complex enough to be it's own post, I will be writing one on just that project alone and that will be here when it releases!

For now, thanks for reading! Keep on making things!
-Will