ROB: the Ultimate R/C NeoPixel/WS2812B LED Display Platform

Published

Introduction: ROB: the Ultimate R/C NeoPixel/WS2812B LED Display Platform

About: Arduino and Robotics Nerd, and alumni of FIRST Robotics Team 5683 (Go R.A.V.E.!). Blinking LEDs with Arduino is still one of my favorite pastimes even after years of doing it.

About a year ago, I went out and got myself 5 meters of WS2812B LEDs, more commonly referred to as "NeoPixels" although mine aren't from Adafruit. A few weeks ago, I finally figured out how to use them. So, with my new knowledge, I went out and tried to find something fun to do with them. VU Meter? Yup, did that. Spectrum Analyzer? Well, that's a work in progress. FastLED Fire2012? That replaced any need I had for candles. LED Matrix? Oh yeah.

But what about something new, something that combined some of these things into a new thing, a better thing, something that interests me... something R/C?? Now there's an idea worth working on! My Arduino IR Robot Display Platform (R.O.M.A.N.) got disassembled (and Instructabled) last summer... Maybe it's time for Rev. 2.

Introducing "ROB", the Strobe R/C Robot.

The design is simple and completely open source: A two wheel drive rover base, with an Arduino Uno for navigation and secondary displays/extra sensors, with an Adafruit Motor Shield to power the wheels. On top we have an Arduino Mega to run the main display: a 8x10 LED Matrix made from 8 rows of 10 LEDs each, ZigZag pattern. This can be replaced by any other WS8212B/NeoPixel compatible individually addressable LED Matrix, but this is the only one I've got so it's what I'll use. Other LEDs will be in use around the edges of the robot for secondary effects as well. All of the parts (except maybe the Uno) can be switched for other components to suit individual users' needs, hence the open source part.

The remote will be a custom, Arduino Nano-based IR controller, because RF is difficult to use with Arduino and this robot is more likely to be for indoor, dim-room, or nighttime use due to the LEDs, as sunlight will diminish their awesomeness considerably.

I have calculated the approximate cost as €120 (USD $135), so this is not a cheap project unless you already have most of the parts (like I did).

So, without further ado...

Step 1: Gathering Materials

I say this in every Instructable, but it's always a good idea to have what you need when you need it (this is a great example of not-so-common Common Sense). This allows you to avoid "Gosh-Darn-It" moments and other profanities. The links are approximations of the parts I have in my tool kit already (the beauty of open source), so don't be surprised if mine look different.

Please note: The links below are affiliate links to Gearbest unless otherwise specified; if you should choose to purchase items through these it will help support my projects here on Instructables. These are not the only options for materials, all of these parts can be found elsewhere and the project is open source, so please do not feel forced to use these links.

Materials: You will need to mix and match some of the links to suit your needs, should you use them.

Arduino Uno (or clone) Uno

Arduino Mega (or clone) Mega

Arduino Nano (or clone) Nano

Tip: If you find an Arduino Starter Kit, it will come with a lot of the parts we use here, in addition to the Arduino board, usually for less money. They are also less of a hassle to find. Mega 2560 Kit W/ LEDs, Buttons, Breadboard and Wires

Paper

Cardboard

Wire (Solid core insulated electrical wire, Dupont jumpers and modelling wire will be needed.)

2 Switches (optional) bulk Slide Switches

3 Momentary Pushbuttons Buttons

3 Infra-Red LEDs (I harvested mine from old remotes, so I don't know the specs, but these should work okay)

3-pin IR receiver IR Receiver Board

6x Any Color 5mm clear or diffused lens LEDs (orange are what I used)

5x Red 5mm clear or diffused LEDs

Assorted LEDs

Joystick module with button Joystick breakout board

Large Breadboard Breadboard

3 - 5 meters Neopixel/ WS2812B LED Strip (60 LEDs/Meter) LED StripAND/OR any NeoPixel-compatible LED Matrix 16x16 LED Matrix (not affiliate links)

Motor Driver board/shield/chip (doesn't matter which one, it just needs to be able to run 2 motors. I use the Adafruit Motor Shield V1) L293D Motor Driver (Adafruit Motor Driver V1 Clone)

Battery Boxes -you will want one with 4 AAs for the Nano and one with 6 AAs for the motors (see Step 3 of my other project for how to get recycled ones) 4AA Battery Box6AA Battery Box

A 2WD Rover/Car Base Complete Car Kit (Uno, Base, Motor Diver, 6 AA Battery Box and Sensors)

This link is for a base which I haven't tried, but it is a great option that looks cool and should work the same as the one I use: Tank-Style Treaded Base

Tip: If you go on Amazon/Gearbest and type in "Arduino Robot Car", you are guaranteed to find tons of different brands of two and four wheeled "smart", "WiFi" robot rover kits that have no WiFi capabilities whatsoever (without additional shields) and only have minimal computing power. They are also dead cheap, and come with (almost) everything you need to run them. (Some don't come with motor drivers, others without the Arduino board needed to run it.) I recommend finding one of these as a DIY kit, as it should come with some of the other needed components (Uno, Motor Driver, various sensors if you're lucky) for a lower overall cost.

Step 2: Tools and Batteries

Just like materials, it is a good idea to have all the needed tools and batteries to complete a project.

Tools Needed:

Soldering iron

Hot glue gun

Screwdriver

Scissors

Multimeter

Tape

Black Acrylic Paint

Paint Brush

Pencil

Ruler

2x Printer cable for programming Mega and Uno (should come w/ the Arduinos)

Mini USB cable for programming the Nano Mini USB to USB cable

Batteries:

Portable USB battery (for the Mega and lights.) 10,000 mAh Power Bank (2 ports)

Tip: If you get a larger battery, it will be harder to mount but will give you more run-time. The one I linked here is quite sufficient for most usage, although I use a smaller one with less battery life (RAVpower 3350 mAh found here on Amazon <= not an affiliate link btw). The one linked ^above^ will also be able to simultaneously supply power to the Uno if you prefer separate logic/motor power supplies.

10x AAs (I recommend rechargeables, this project will go through a lot of batteries otherwise)

Step 3: BOM Links

This is a complete list of links that should supply you with everything you need to complete this project. Other links from the BOM can be mixed and matched, but this is what I recommend getting.

Please note:The links below are affiliate links to Gearbest unless otherwise specified; if you should choose to purchase items through these it will help support my projects here on Instructables. These are not the only options for materials, all of these parts can be found elsewhere and the project is open source, so please do not feel forced to use these links.

Nano

Mega Kit w/ LEDs, breadboard, buttons, wires, and more

Slide Switches

IR LEDs

IR Receiver Board

Joystick Module

LED Strip (non-affiliate link to Amazon, get the 5m 60 LEDs per Meter option)

Complete Car Kit (Uno, Base, Motor Diver, 6 AA Battery Box and Sensors)

Power Bank (2 Ports, 10,000 mAh)

4 AA Battery Box

Mini USB to USB cable

TOTAL COST: about €125 ( USD $140) not including shipping or tax

I built this mainly with parts I already had, so it was significantly cheaper for me. A lot of these parts can be substituted for similar items that you may have, so don't be afraid to hack a bit to get yours working without busting your wallet.

Step 4: The Rover Base

"Yeah, they see it rollin', and it's blinkin'...."

So, in order for us to have a robot, we must first have a base to mount said robot on. I decided to use a simple acrylic two-wheel drive base for mine. In the Materials list two steps back I also added a tank style alternative which will be better if you have rough or carpeted floors. The internal layout of the robot will different for that base, however, so if you choose that one you will have to figure it out yourself. (I may come back later when I have more budget and add a step or a new project for that one as well, but for now I just have the 2WD base.)

Step 1: Assemble the base.

The base kit I recommend should come with instructions for building the base; simply follow those to assemble it. If your kit did not come with instructions, follow the image above. Your base should resemble mine when finished. BTW, you can paint the wheels like I did to individualize your robot and make it look cooler. I used gloss red acrylic paint for the inside and hammered bronze spray paint for the outside on mine. It looks much better than the original yellow.

Step 2: Add the Battery Box

There should be two small screws and corresponding hex nuts left over after assembly. Use these to mount the battery box on the rear of the robot, as shown above.

Step 3: Mount the Portable USB Battery and Arduino Mega

Depending on which USB battery you use, the mount may be different. I used two hex shafts with a piece of plastic screwed on top, and the battery just slides in; the back resting on the acrylic that is used to mount the right-side motor. If you got the battery I recommended, you should be able to zip-tie it down in roughly the same place instead.

The Mega should be mounted alongside the USB battery. I used hex shafts, but you could also hot-glue it, use sticky Velcro tape, tape it, or just zip-tie it in place. Just make sure it doesn't touch or get too close to the wheel.

Step 4: Mount the Uno

First, slot the Motor Shiled V1 on top of the Uno. If you are using a different motor driver, disregard this step and mount the motor driver later.

Using sticky Velcro tape (mine is 'industrial', btw) attach the Uno to the underside of the base, in front of the motors. Alternative methods are double sided tape and zip-ties.

Step 5: Wire the Uno (Schematic in pictures)

Thread the wires from the battery box through the central hole in the base, and attach them to the Power block on the Motor Shield. Again, if you have a different motor driver, disregard this. You will need to wire the power to both Vin and GND on the Uno and VCC and GND on your motor driver, so that they run in parallel to each other.

Wire the two motors to the motor 3 and motor 4 block (on the same side) of the shield. This will be the side opposite the programming port on the Uno. If you do it backwards you will need to switch them around later (Don't worry, I do it every time).

EDIT: If you used a L298 motor driver instead, attach Motor A to pins 4 and 7, and Motor B to pins 8 and 9.

Using Female-Female jumpers, wire the IR receiver to A0, GND, and 5V on the Motor Shield/Uno. You may have to add pin headers to the motor shield to do this. Then, bend the pins down so that they are at a 90 degree angle to the board. (This is so they don't catch or scrape on the floor).

Also, note that I wired my receiver wrong and fried it, and used a spare instead, so don't follow the wiring in the pictures, use the schematic instead. Look up the specs of your part to find which pins are which if it isn't labeled.

Fasten the Wires to the middle of the underside of the base using tape, so that they won't touch the floor.

Step 6: Mount the IR Reciever

Remove the rear swivel wheel.

Using tape of some sort, fasten the wires to the underside of the base so that the receiver sticks out to the rear, facing up when the rover is right-side up.

Re-install the swivel wheel, screwing through the tape to further reinforce the receiver's position (which should be directly between the mounting posts for the wheel).

Tape down any extra length of wire in the center.

And now you are ready to move on to the Matrix!

Step 5: Building the Matrix

"Unfortunately, no one can be told what the Matrix is. You have to see it for yourself." - Morpheus (The Matrix, 1999)

Well, now we have digital cameras and YouTube, so you don't really have to experience it first person to believe it. However, no description I write here could ever do justice to the awesomeness of a well-built LED Matrix. So how about I just tell you how to build one, and then you get the experience of plugging it in and (hopefully) seeing the beauty of your handiwork bloom into a rainbow of color and fascinating oscillations of light.

Note: These steps mostly apply if you bought an LED strip; if you already have a matrix you can move on. I do suggest reading through anyway, as it will lend you a better understanding of Matrices in general. I also suggest you run the test codes to make sure your matrix works properly.

Ensure your LED strip is in fact 60 LEDs per meter, not 30. 140 LEDs per meter strips are expensive but will work about the same.

If your strip has silicone insulation, you may want to gently peel it off to make everything easier later on, as we do not need the strips to be waterproof.

Step 1: Test your LEDs

Download and install the Adafruit NeoPixel, Adafruit NeoMatrix, and Adafruit GFX libraries to your IDE. All are linked here. You will need to use the one of the newer versions of the Arduino IDE for this to work properly.

Choose your Matrix size. Mine is 8x10, so I have 80 LEDs. Keep in mind that the bigger the Matrix, the more trouble you will have powering it and the more program memory you will need on the Mega. Note that 8x10 is the perfect Matrix dimensions for the 2WD base.

Open the 'strandtest' example from the Adafruit NeoPixel examples folder (Open>libraries>Adafruit NeoPixel>examples>strandtest)

Scroll down to Line 16. Delete the number 60 and replace it with the number of LEDs you calculated earlier (in my case 80).

Upload the code to the Mega, then unplug it. (otherwise you can fry LEDs while wiring them)

Wire GND on the LED strip to GND on the Mega.

Wire Din (center pin) on the LED strip to pin 6 on the Mega. If you aren't lazy like me, you may want to put a small 300-500 ohm resistor in between these two pins to 'reduce NeoPixel burnout risk' as the code puts it.

Wire 5v on the LED strip to VInon the Mega, NOT the 5v pin (5v won't allow enough amps through, VIn will).

Again, if you aren't lazy like me, you can put a 1000 uF capacitor in between Power and GND to smooth out the power supply and again to 'reduce NeoPixel burnout risk'.

Plug the Mega back in and make sure the first 80 (or whatever number you put in place of 60) of the LEDs are working properly. Things to check for are dim, off-color, or burnt out LEDs. Mark these in some way so you remember which ones they are.

Unplug the Mega after you've watched the pretty colors for a bit.

Step 2: Cutting the Strip

Decide what orientation you want the strips in your Matrix. This will affect your code later as well. I chose Rows, as apposed to Columns. This makes scrolling text look better, and also streamlines the look of the robot.

Since my Matrix is 8 tall and 10 wide, I will be cutting 8 lengths of 10 LEDs each. Do a similar calculation for your dimensions and orientation.

Cut the LEDs as you have calculated, using the designated lines that are pre-printed on the strip.

Cut out any of the bad LEDs from the last step. If you are lucky, there won't be any.

From the leftover LEDs, cut replacements for the bad LEDs after carefully testing them with the Mega. Use extreme caution and ensure that GND never at any point becomes disconnected while Power and Din are running.

Step 3: Soldering

Carefully solder together the replacement LEDs, ensuring the data arrow is pointing the right direction. Test these after the solder cools down. I had an inordinate amount of LEDs stop working after I soldered them.

For every section of LED strip, cut 3 sections of solid core wire (stranded core doesn't seem to work, I tried), each 1.5 - 2 inches or so in length.

Strip the ends of each of these wires.

Note: You can use Dupont jumper cables instead to avoid some of the hassle.

Solder each section of LED strip together in a straight line, with the data arrows all pointing the same direction.

Test the strip after you add each section to make sure it works; if only part of it works go back and check all of your connections and LEDs again. (This part is annoying and takes forever. I spent a weekend trying to get mine to work.)

This is a good point to solder the capacitor and resistor to the first LED, if you want to be safe and reduce the risks of pixels burning out (I didn't and mine work just fine).

Once all of your sections are connected, you should have 3 wires left over. Solder these to the first LED. I used jumpers instead, because that makes it easier to connect to the Mega later.

Step 4: Make a background

On some paper, mark the length of one pixel from the cut lines on the strip. Using this length, form a grid with the dimensions of your Matrix. When aligned to the grid, all pixels should be evenly spaced in both directions.

Crease the paper along the grid lines.

Paint the paper black to match your strip, and let dry.

Cut a piece of cardboard that is about the same dimensions as your background.

Align and glue the background to the cardboard. You can also tape the edges with transparent Scotch tape to secure it better.

Step 5: Stick the LEDs

After the glue has dried, peel the backing off of the first section of LEDs in your strip.

Carefully align it to the proper crease marks on the paper, and then firmly stick it down. If you chose Rows as your orientation, your first section should be running from left to right across the very top row. If you chose Columns, your first strip should be from top to bottom along the far left side. Each pixel should be centered in a box of the grid.

Bend the next section at the wires so that it is parallel to the first strip, peel the backing off, align it to the next row/column of crease marks, and firmly stick it to the background, again making sure the pixels are centered properly.

Repeat until all the strips are neatly stuck to the background. Your Matrix should now look very similar to mine.

Step 6: Testing the Matrix

First, plug the strip into your Mega (the one with the strandtest uploaded to it) Use the same wiring as for testing the strip.

Plug in the Mega, and the Matrix should light up and run the strandtest as if it were a normal LED strip. Check to make sure all the LEDs function properly.

Now, you can start coding it like a proper Matrix. The NeoMatrix library examples are a good place to start. Choose and upload one of these, making sure to read the code and change the settings to match your Matrix.

I suggest watching a few videos on YouTube about LED matrices, as that is where most of my knowledge on the topic originates. It will also help you understand the code part better.

Step 6: Knight Rider, Beacon Lights, and More NeoPixels!

This is the rear, uh, 'casing' shall we call it, that hides the battery box and supports the rear of the Matrix.

Step 1: Cardboard (or is it cardbord? Maybe cardbored? What about cardboared? Eh, whatever.)

Cut three lengths of cardbored, each about 1 inch tall, one the width of the back of the base, and two about the length from just behind the wheels to the rear of the base.

Poke 5 evenly spaced holes in the center of the largest piece of cardbord.

Paint the three pieces of cardboared black, then glue them together to form a 'U' with the longest piece as the bottom and the smaller pieces across from each other as the sides.

Step 2: Knight Rider LEDs

Slot 5 Red LEDs into the holes in the longest piece of cardboard, and glue them in place.

Solder the cathodes (short legs) of the LEDs together.

Cut 5 lengths of wire 5 inches long. Strip the ends.

Solder the wires to the anodes (long legs) of the LEDs.

Step 3: Beacon Light (this step is the same as in my Arduino IR Robot Display Platform, because I recycled the beacon from that).

No robot worth it's bolts doesn't have a beacon light of some sort, and that includes this one. I built my beacon with six orange LEDs, wire, paper, hot glue, and a soldering iron. It can simulate a rotary beacon as well as pulse, blink and fade. You can build it with whatever color LEDs you want, but you will need 6 of them.

Sub-Step 1: Bend and Glue

Bend the legs on each LED to a 90 degree angle, making sure that the cathode is always on the left when the back of the LED is facing towards you and the leads are pointing down.

Cut out a small circle of paper, about half an inch in diameter.

Glue 2 LEDs directly across from each other on the circle.

Glue the remaining four LEDs on either side, each directly across from another, and all evenly spaced.

Fill in the gaps with hot glue (not required, but it makes everything else easier)

Bend the cathodes towards the center, and twist them together.

Sub - Step 2: Wires and Solder

Cut 7 lengths of insulated wire, each about an inch and a half long, and strip each end (solid core works best)

Solder the cathodes together, then solder on a wire from step 6

Solder the remaining wires to the anodes of the LEDs.

Arrange the unoccupied ends of the wires in a row, cathode first, then each LED in order around the circle.

Sub-Step 3: Mount and Glue

Cut a slit in the longest piece of cardboard, on the top-left corner above the red LEDs.

Insert the wires from the beacon through, then glue them in place.

Carefully bend the beacon to a 90 degree angle, so it is pointing up and away from the red LEDs. Make sure no wires are crossing.

Sub-Step 4: Solder

Cut 6 lengths of wire 5 inches long, preferably in a different color to the wires on the red LEDs. Solder these to all the wires except ground (the cathode).

Cut another wire 5 inches in length, then a small one about an inch long.

Strip the ends of these wires.

Solder the short wire in between the cathodes of the red LEDs and the beacon cathode.

Solder the long wire to the cathodes of the red LEDs

Step 4: NeoPixels!!! (Again!! Isn't this fun?)

Cut and test 2 lengths of 5 NeoPixels each. Solder the 5V pins of the first LEDs together with a long jumper wire.

Solder another jumper to 5V on only one of the strips.

Solder jumper wires to GND on each strip.

Solder jumpers to Din on each strip.

Solder the long wire from the cathodes of the LEDs to GND on one of the strips.

After the solder has cooled, test each strip.

Peel the backing off of the strips, and carefully stick them to the sides of the rear 'casing'.

Step 5: Mount the rear 'casing' (see next step for pictures)

Align the 'casing' to the back of the base, so that the beacon is pointing up and the sides hide the battery box.

Glue the back section in place.

If your sides do not align to the sides of the base, follow the below steps. Otherwise, glue your sides in place.

My sides did not align, but rather stuck out a little on each side. This is a simple thing to fix.

First, cut two pieces of cardboard about 1 inch by 3 inches.

Glue these to the underside of the back of the base, so that the 3 inch edge aligns to the bottom of the sides of your 'casing'.

Glue the bottom edge of the sides of the 'casing' to the cardboard supports, making sure that the top edge of the sides remain parallel to the base. You may want to put cardboard "spacers" in between the two to do this.

You are now ready to move on to Wiring!

Step 7: Final Wiring and a Mount for the Matrix

Wires are mystical things. They are solid, and yet they allow the magical smoke of circuitry flow though them, transmitting power and data. Whatever you do, be careful and don't let this smoke out of the circuit, else it may never work again.

Step 1: LEDs

Wire the Red LEDs in order on Mega pins A7 through A12.

Wire the Beacon LEDs in any order on Mega pins 22 through 27. You will need to change the code later to sequence these properly, but that will be easier than testing each wire by hand (trust me- I designed the code to make this easy after toiling through it with the 50-odd versions of my last robot).

Step 2: NeoPixels

Wire GND from the NeoPixel strips to the closest open GND pin on the Mega.

Wire Din from the NeoPixels to Mega pins 2 and 3.

Wire 5V from the NeoPixels to 5V on the Mega.

Step 3: Signal wires from the Uno

Using Male-Female jumpers, wire A5, A6, and GND from the Mega to A1, A2, and GND, respectively, on the Uno. To keep your wires tidy, thread them through the square hole in the center of the base and tape them down after you finish. Also, bend any wires on the Uno so that they won't touch the floor.

Step 4: The Matrix

Wire 5V and GND on the Matrix to Vin and GND, respectively, on the Mega.

Wire Din on the Matrix to pin 6 on the Mega.

And now to mount the Matrix. I used modelling wire and some cardboard to create a hinged mount that allows access to the wires and batteries underneath, but also holds the Matrix flat and steady in the closed position.

Step 1: Cardboard

Place your Matrix on top of the Uno, so that the first LED is at the front of the base, above the Mega, and the rear aligns to the back of the 'casing' we made.

Mark the location of the sides of the 'casing' on the underside of the Matrix.

Cut two pieces of cardboard the same length as your sides and about 1 cm tall.

Paint these black.

After the paint has dried, hot glue the pieces to the underside of your Matrix where you marked previously. When the glue has dried, your Matrix should be able to slide back and forth on the 'casing' but not wiggle from side to side.

Cut off any cardboard that overlaps on the NeoPixel strips when the Matrix is placed over the 'casing'.

Step 2: Modeling wire (I use 18 AWG solid copper wire, but 18 - 22 AWG steel wire should work as well)

Cut a length of about 12 inches of wire and straighten it.

Poke the wire horizontally through the cardboard back of the Matrix to form a hinge.

Center the wire so there is an equal length on each side of the Matrix, then bend it down to a 90 degree angle on either side.

Slot the wire through the base of the rover, and center the Matrix so the back and sides of the 'casing' are aligned properly and the matrix sits comfortably on top. (bend any other wires that get in the way)

Wrap and thread the wire around and through the base enough times to secure it.

Cut off any extra wire.

Step 3: USB Power

This step is optional but recommended. if you choose to skip this step, simply use a short programming cable to power the Mega.

Cut a spare programming cable about 2 inches from either end.

Expose and strip the 4 wires inside each end.

Solder the ends back together, matching the wires by color.

Use electrical tape to insulate the joints individually, and then wrap some around the whole thing as additional protection.

Plug the USB end into the portable battery. The other end we will plug into the Mega after we program it.

And done! You can now move on to make a remote to control your robot with.

Step 8: A Custom IR Remote

So, after having gotten fed up over the crappy range and the sluggish response of the little IR remotes that come with most Arduino kits, and multiple failed attempts to use remotes from old r/c helicopters, cars, and Hexbugs, I decided to just give up and build my own (and it isn't much better [yet]). I used a Nano as the processor, and decided on a console-style design for the controls. A standard breadboard is the perfect size for this, and that made everything really easy. I used a joystick breakout module and three pushbuttons in this iteration, and it wouldn't be at all hard to add a fourth button or even a second stick if I wanted to. I decided to use the stick to drive the robot, and the four buttons (there's one built into the joystick) to cycle through display modes.

So let's get cracking! If you are comfortable with schematics, follow the one above. Otherwise, I transcribed it below.

Step 1: Nano

My Nanos didn't come with pre-soldered pin headers, and I assume yours didn't either. Solder male pin headers on to the Nano, minus the 2x3 ICSP header (or whatever that thing I never use is called).

Bread the Nano on the center of the breadboard.

Step 2: Buttons

Tip: Use solid core wire in short lengths instead of Dupont jumpers to reduce the amount of extra wire in your way.

Bread 3 pushbuttons on the same side of the breadboard as the USB port of the Nano. You can put them in whatever configuration is comfortable to you, so long as no pins are overlapping.

Pick a side on each button, and wire it to the Ground rail at the top (when the USB port is pointing left, see the image above) of the breadboard.

Wire the other side of each button to pins A0 through A2 on the Nano.

Step 3: Joystick

Wire VCC and GND from the joystick to 5V and GND on the Nano.

Wire the button pin to A3 on the Nano.

Wire the X axis pin to pin A4 and the Y axis pin to pin A5 on the Nano.

Step 4: IR LEDs

Bread the LEDs in the top row of the breadboard, with the Cathodes (short legs) in the Ground row and the Anodes (long legs) in the other row.

Connect the row with the Anodes to pin 9 on the Nano. (might need changing later)

Step 5: Grounding and Power (Note: the diagram shows AAA batteries, you should have AAs)

Connect the Ground row at the top of the breadboard to Ground on the Nano.

Connect the negative (black) lead of the battery box to GND on the Nano.

(Optional) Wire a side pin of a slide switch to Vin on the Nano, and the positive (red) wire of the 4 AA battery box to the center pin of the switch.

If you chose not to follow the above, simply connect the red wire of the battery box to Vin on the Nano to turn the Nano on, and disconnect it to turn the Nano off. Leave it disconnected for now.

Finished! You can now move on to the Programming aspect of this project.

Step 9: Programming! (Finally!)

So, you now have a robot and a remote. All you need is to program them. Good luck....

Just kidding. I will provide you with the code for each, but keep in mind, there is a lot that can be improved. Some of the things I am working on currently is running two of the built in displays simultaneously, because the current version can only run one of the three at a time, so I have to choose whether I want to run the beacon and Knight Rider LEDs, the side LEDs, or the Matrix, but I can't use all at once because of conflicting delays in the functions and for() loops. Also, the displays won't deactivate when another is activated, which should be relatively easy to fix, I just haven't had the time.

Another thing that needs work is the controls. I use spam logic with my controller; it just keeps sending the signal in the hope that the receiver will get it. The way I have it set up, the controls need to be Line-of-Sight to the receiver to work as advertized. I am working on a version that uses RF transmitters and receivers so that I can get more response over longer distances. However, progress has been slow so I'm stuck improving this code until I get V2.1 up and running.

You will need to download and install the libraries I linked here for the code to work.

EDIT: I added a bit to the Uno Drive Code to account for a L298 motor driver in addition to the Adafruit one I use.

//IRcontroller.ino for the remote
#include <IRremote.h>  // initialize the library

IRsend irsend;         // Supposedly this is pin 3. On mine it ended up being pin 9. 
                       // Test the pwm pins with a red led to find which one blinks when you send a signal, 
                       // then attach your ir leds to that pin.

const int stickX = A3;  // the joystick pins
const int stickY = A4;
const int buttonUp = A0;  // the number of the pushbutton pins
const int buttonDown = A2;
const int buttonLeft = A1;
const int buttonStick = A5;

//Below are all the variables that the code uses to debounce the buttons and read the joystick position. 
//You won't need to mess with any of these unless you add more buttons or joysticks.

int up = 0; int down = 0; int right = 0; int left = 0; int stick = 0; int x = 0; int y = 0;
int sum = 0;
int xIn;
int yIn;
int xVal;
int yVal;
int upState;             // the current reading from the input pins
int downState;
int leftState;
int stickState;
int lastUpState = HIGH;       // our buttons are active low
int lastDownState = HIGH;
int lastLeftState = HIGH;
int lastStickState = HIGH;     // the previous reading from the input pins
unsigned long lastDebounceUp = 0; // the last time the output pin was toggled
unsigned long lastDebounceDown = 0;
unsigned long lastDebounceLeft = 0;
unsigned long lastDebounceStick = 0;
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void debounce(){                                          //Make debouncing a function to save space in the main loop. It also makes it really easy to disable the buttons.
  // read the state of the switch into a local variable:
  int readingUp = digitalRead(buttonUp);
  int readingDown = digitalRead(buttonDown);
  int readingLeft = digitalRead(buttonLeft);
  int readingStick = digitalRead(buttonStick);

  // check to see if you just pressed the button (i.e. the input went from LOW to HIGH), and you've waited long enough since the last press to ignore any noise:
 
  if (readingUp != lastUpState) { // If the switch changed, due to noise or pressing
    lastDebounceUp = millis(); // reset the debouncing timer
  }
  if (readingDown != lastDownState) {
    lastDebounceDown = millis();
  }
  if (readingLeft != lastLeftState) {
    lastDebounceLeft = millis();
  }
  if (readingStick != lastStickState) {
    lastDebounceStick = millis();
  }

  if ((millis() - lastDebounceUp) > debounceDelay) { // whatever the reading is at, it's been there for longer than the debounce delay, so take it as the actual current state:
    if (readingUp != upState) { // if the button state has changed:
      upState = readingUp;
      if (upState == LOW) { //run this function only if th button is low and wasn't low before.
       goForward();
       up = 0;
      } 
    }
  }
    if ((millis() - lastDebounceDown) > debounceDelay) {   //repeat for each button
    if (readingDown != downState) { 
      downState = readingDown;
      if (downState == LOW) { 
       goBackward();
       down = 0;
      } 
    }
  }
    if ((millis() - lastDebounceLeft) > debounceDelay) { 
    if (readingLeft != leftState) { 
      leftState = readingLeft;
      if (leftState == LOW) { 
       turnLeft();
       left = 0;
      } 
    }
  }
    if ((millis() - lastDebounceStick) > debounceDelay) { 
    if (readingStick != stickState) { 
      stickState = readingStick;
      if (stickState == LOW) { 
       lightOn();
       stick = 0;
      } 
      
    }
  }
  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastUpState = readingUp;
  lastDownState = readingDown;
  lastLeftState = readingLeft;
  lastStickState = readingStick;
}

void goForward(){                   //these functions are what send the signals
  
  irsend.sendNEC(0x12341234, 32); // all this is is a random set of numerals I typed in with what I think is a 32 bit signature. I dunno, I didn't memorize the "readme" file for the IRremote library.
  digitalWrite(13, HIGH);         // blink the built in LED to tell me the code was sent.
  delay(40);
  digitalWrite(13, LOW);
  
}

void goBackward(){                   //same thing, different numbers. 
                                     //The receiver is supposed to read these numbers the exact way they are typed here, but mine will only do it short-range due to atmospheric light distortion (I think)
  irsend.sendNEC(0x43214321, 32);    //which means you need to go through and test the controller with the IRrecv Demo code on the receiving end to find what exactly is being received
  digitalWrite(13, HIGH);
  delay(40);
  digitalWrite(13, LOW);
  
}

void turnRight(){
  
  irsend.sendNEC(0x32413241, 32);   //etc.
  digitalWrite(13, HIGH);
  delay(40);
  digitalWrite(13, LOW);
  
}

void turnLeft(){

  irsend.sendNEC(0x23142314, 32);
  digitalWrite(13, HIGH);
  delay(40);
  digitalWrite(13, LOW);
  
}

void lightOn(){
 
  irsend.sendNEC(0x80808080, 32);
  digitalWrite(13, HIGH);
  delay(40);
  digitalWrite(13, LOW);
  
}

void readX(){                        //find the analog position of the joystick
  xIn = analogRead(stickX);
  xVal = map(xIn, 0,1023, 0, 255);
}
void readY(){
  yIn = analogRead(stickY);
  yVal = map(yIn, 0, 1023, 0, 255);
}

void determineStick(){               // and then send a signal accordingly. I haven't yet added codes for diagonal positions, so right now it's just -, <, ^, v, or >.
  if (xVal >= 137){
    x = 0;
   
    irsend.sendNEC(0x56835683, 32);
    digitalWrite(13, HIGH);
    delay(40);
    digitalWrite(13, LOW);
    
  }
  if (xVal <= 117){
    x = 0;
   
    irsend.sendNEC(0x38653865, 32);
    digitalWrite(13, HIGH);
    delay(40);
    digitalWrite(13, LOW);
    
  } 
  if (yVal >= 137){
    y = 0;
    
    irsend.sendNEC(0x68536853, 32);
    digitalWrite(13, HIGH);
    delay(40);
    digitalWrite(13, LOW);
    
  } 
  if (yVal <= 117){
    y = 0;
    
    irsend.sendNEC(0x35863586, 32);
    digitalWrite(13, HIGH);
    delay(40);
    digitalWrite(13, LOW);
    
  }
  if (xVal >= 117 && yVal >= 117 && xVal <= 137 && yVal <= 137){  //stick is centered
   
    irsend.sendNEC(0x34566543, 32);  //this is the halt signal. Very important if you want to not crash.
    digitalWrite(13, HIGH);
    delay(40);
    digitalWrite(13, LOW);
   
  }
}

void sendVal(){          //this is for debugging purposes, it just prints the state of the controls to the serial monitor
  Serial.println(xVal);
  Serial.println(yVal);
  Serial.println(upState);
  Serial.println(downState);
  Serial.println(leftState);
  Serial.println(stickState);
}
void setup(){                          //initialize everything
   pinMode(buttonUp, INPUT_PULLUP);
   pinMode(buttonDown, INPUT_PULLUP);
   pinMode(buttonLeft, INPUT_PULLUP);  //use the internal pullup to ensure there are no 'floating' pins
   pinMode(buttonStick, INPUT_PULLUP);
   pinMode(stickX, INPUT);
   pinMode(stickY, INPUT);              // these are analog potentiometers, so a pullup is pointless
   Serial.begin(9600);       //debugging only
}

void loop() {
//  sendVal();  // uncomment for serial debugging
 debounce();   //debounce the buttons
 readX();      //get the joystick positions
 readY();
 determineStick();  //send signals accordingly
 delay(10);        //let the processor rest before looping again
}
// UnoDriveCode.ino for the Uno motor driver
#include <AFMotor.h>
#include <IRremote.h> //initialize the libraries

IRrecv irrecv(A0); //define the ir pin
decode_results results; //this is where it stores the received code

AF_DCMotor motorRight(3, MOTOR34_64KHZ); // initialize the motors
AF_DCMotor motorLeft(4, MOTOR34_64KHZ);

#define driver1  //change 1 to 2 if you use the L298 driver, 1 is for the Adafruit driver
 
 //vars for L298 motor driver
//Pins for motor A 
const int MotorA1 = 4;
const int MotorA2 = 7; 
//Pins for motor B 
const int MotorB1 = 8;
const int MotorB2 = 9;

int f;  //these are the variables I use to determine what function to run
int b; 
int l;
int r;
int h = 1;
int up;
int down;
int stick;
int left;
void modeFinder(){ //this determines what displays are used by the Mega
  if (up == 1){
    analogWrite(A1, 255);
    analogWrite(A2, 0);
  };
  if (down == 1){
    analogWrite(A1, 0);
    analogWrite(A2, 255);
  };
  if (left == 1){
    analogWrite(A1, 0);
    analogWrite(A2, 0);
  };
  if (stick == 1){
    analogWrite(A1, 0);
    analogWrite(A2, 255);
  };
}
#ifdef driver1 
void fd (){ //these are the drive methods. they don't use delays because that will interfere with the IR code
  motorRight.run(FORWARD);
  motorLeft.run(FORWARD);
}
void bk (){
  motorRight.run(BACKWARD);
  motorLeft.run(BACKWARD);
}
void lt (){
  motorRight.run(RELEASE);
  motorLeft.run(FORWARD);
}
void rt (){
  motorLeft.run(RELEASE);
  motorRight.run(FORWARD);
}
void halt (){
  motorLeft.run(RELEASE);
  motorRight.run(RELEASE);
}
#endif
#ifdef driver2 
void fd (){ //these are the drive methods. they don't use delays because that will interfere with the IR code
   digitalWrite (MotorA1, HIGH);                              
   digitalWrite (MotorA2, LOW); 
   digitalWrite (MotorB1, HIGH); 
   digitalWrite (MotorB2, LOW);
}
void bk (){
  digitalWrite (MotorA1 , LOW);                              
  digitalWrite (MotorA2, HIGH); 
  digitalWrite (MotorB1, LOW); 
  digitalWrite (MotorB2, HIGH);
}
void lt (){
  digitalWrite (MotorA1, LOW);                              
  digitalWrite (MotorA2, LOW); 
  digitalWrite (MotorB1, HIGH); 
  digitalWrite (MotorB2, LOW);
}
void rt (){
  digitalWrite (MotorA1, HIGH);                              
  digitalWrite (MotorA2, LOW); 
  digitalWrite (MotorB1, LOW); 
  digitalWrite (MotorB2, LOW);
}
void halt (){
  digitalWrite (MotorA1, LOW);                              
  digitalWrite (MotorA2, LOW); 
  digitalWrite (MotorB1, LOW); 
  digitalWrite (MotorB2, LOW);
}
#endif
void translateIR(){     //this translates a HEX value from the IR code into something more useful
  switch(results.value){      
  //joystick stuff:  
    
  case 0x6B85EA37:      //these values may be different based on your transmitter and receiver. Use the IRrecv Demo code to determine what does what on your system.
    f = 1;         // go forward
    b = 0;
    l = 0;
    r = 0;
    h = 0;
    break;
  case 0xC4BB93AF:  
    b = 1;         // go backward
    f = 0;
    l = 0;
    r = 0;
    h = 0;
    break;
  case 0xDB867814:  
    r = 1;         //turn right
    l = 0;
    f = 0;
    b = 0;
    h = 0 ;
    break;
  case 0x2A008D37:  
    l = 1;        //turn left
    r = 0;
    f = 0;
    b = 0;
    h = 0;
    break;
//   button stuff:
  case 0x37E66545:  
    stick = 1;     //enable a mode
    up = 0;
    left = 0;
    down = 0;
    break;
  case 0xD3C482CC:  
    up = 1;        //enable a different mode
    down = 0;
    stick = 0;
    left = 0;
    break;
 case 0x8E2CCDCC:  
    left = 1;      // etc.
    up = 0;
    down = 0;
    stick = 0;
    break;
  case 0xDE3E4AE7:  
    down = 1;
    up = 0;
    left = 0;
    stick = 0;
    
    break;
    
  case 0x1ADA75F7:  
    f = 0;           // VERY IMPORTANT: this is the Halt function that stops the motors. Set this to the code received when the stick on the controller is in the center position.
    b = 0;           // If nothing else, this is the part you want to work most properly. Otherwise your robot will crash. A lot. Trust me. I found out the hard way.
    l = 0;
    r = 0;
    h = 1;
    break;
  };
}
void setup (){
  irrecv.enableIRIn();  //start the receiver
  pinMode(MotorA1, OUTPUT); 
  pinMode(MotorA2, OUTPUT); 
  pinMode(MotorB1, OUTPUT); 
  pinMode(MotorB2, OUTPUT);
  digitalWrite(MotorA1,LOW);
  digitalWrite(MotorA2,LOW);
  digitalWrite(MotorB1,LOW);
  digitalWrite(MotorB2,LOW);
  motorRight.setSpeed(250);  //set the motor speeds. I have them at max, but I would suggest turning these down until you get used to the controls.
  motorLeft.setSpeed(250);
  pinMode(A1, OUTPUT);       //set these as outputs to the Mega
  pinMode(A2, OUTPUT);
}
void loop(){
  if (irrecv.decode(&results)){   // when it receives a signal, it turns it into something useful
    translateIR(); 
    irrecv.resume(); 
  }  
  modeFinder();                    // make sure we have the displays set to do something</p><p>  while(f == 1){                  //when the conditions are met, go forward
    fd();                         
    modeFinder();                  // we still want a display while driving
    if (irrecv.decode(&results)){  // and we want it to be able to stop and run a new code. 
      translateIR(); 
      irrecv.resume(); 
    }  
  };
  while (b == 1){   // same thing, just going backwards
    bk();
    modeFinder();
    if (irrecv.decode(&results)){
      translateIR(); 
      irrecv.resume(); 
    }  
  };
  while (r == 1){
    rt();
    modeFinder();
    if (irrecv.decode(&results)){
      translateIR(); 
      irrecv.resume(); 
    }  
  };
  while (l == 1){
    lt();
    modeFinder();
    if (irrecv.decode(&results)){
      translateIR(); 
      irrecv.resume(); 
    }  
  };
  while (h == 1){                   //And here again is the important part. A robot that drives is great. A robot that drives and can stop driving is better.
    halt();
    modeFinder();
    if (irrecv.decode(&results)){
      translateIR(); 
      irrecv.resume(); 
    }  
  };
  delay(50);                       // let the processor rest
}

// DisplayCode.ino for the Mega
/* 
Please note: a lot of this code is annotated from public examples and other projects I have built. 
It is by no means perfect, and the various parts are scattered about in such a way that even 
I have a hard time keeping track of what came from where and why I have it or what it is used for.
Forgive me for any shortcomings on my explanations here; if you have a question, comment or suggestion,
by all means, please share. This is a learning experience for most of us, anyway, even me.
*/


#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>    //initialize the libraries



#define PIN 6
#define PIN2 2
#define PIN3 3 //define the NeoPixel pins


Adafruit_NeoPixel stripLeft = Adafruit_NeoPixel(5, PIN2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel stripRight = Adafruit_NeoPixel(5, PIN3, NEO_GRB + NEO_KHZ800);  //strip settings. change these if you use different LEDs

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(10, 8, PIN,
  NEO_MATRIX_TOP     + NEO_MATRIX_LEFT +
  NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG,
  NEO_GRB            + NEO_KHZ800);                          // matrix settings. Change these to accomodate your matrix size, pattern, LED density, and the position of the first LED.

const uint16_t colors[] = {
  matrix.Color(255, 0, 0), matrix.Color(255, 135, 0), matrix.Color(255, 255, 0), matrix.Color(0, 255, 0), matrix.Color(0, 255, 255), matrix.Color(0, 0, 255), matrix.Color(255, 0, 255) };

//color presets for the text


// And now, a safety warning from our friends at Adafruit Industries:

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

// Thank you for your patience. You may now continue with the code.

// vars for the displays. I think some are unused, but I'm not sure which.

int bPin[] = {22, 23, 26, 27, 24, 25};    //the beacon pins            NOTE: leave these in an array, it makes timing a lot easier
int d = 55;                               //delay timing
int rPin[] = {A12, A11, A10, A9, A8, A7};  // the scanner pins           "     "     "    "  "   "    "   "     "     "  "   "
int count = 0;                             // this is used for the LED arrays
int timer = 30;                           // not sure about this one

// these are for the Matrix... I think.
int x    = matrix.width();
int pass = 0;

int c = 1;
int s = 1;
int pc;

//display mode vars:

int mode = 0;
int input1;
int input2;

void getModes(){                        //find what mode the Uno is telling us to be in:
  input1 = analogRead(A5);
  input2 = analogRead(A6);
  if (input1 >= 127 && input2 <= 127){
    mode = 0;
  };
  if (input1 <= 127 && input2 >= 127){
    mode = 1;
  };
  if (input1 >= 127 && input2 >= 127){
    mode = 2;
  };
  if (input1 <= 127 && input2 <= 127){
    mode = 3;
  };
}

// the below function is for the simultaneous display of the beacon and the scanner. The delays here are a pain to explain, so I won't unless you specifially ask in the comments.

void beacon(){
  digitalWrite(bPin[0], HIGH); //light 1 on
  delay(d);
  digitalWrite(bPin[0], LOW); //light 1 off, light 2 on
  digitalWrite(bPin[1], HIGH);
  delay(d);
  if (c>=4 || c <= 0 ){       //basically, figure out which scanner led is on, set the next one to turn on, and reverse when it gets to one end or the other.
    s = -s;
  };
  pc = c;
  c = c + s;
  digitalWrite(rPin[c], HIGH);
  digitalWrite(rPin[pc], LOW);
  digitalWrite(bPin[1], LOW); //light 2 off, light 3 on
  digitalWrite(bPin[2], HIGH);
  delay(d);
  digitalWrite(bPin[2], LOW); //light 3 off, light 4 on
  digitalWrite(bPin[3], HIGH); //So on and so forth
  delay(d);
  if (c>=4 || c <= 0 ){
    s = -s;
  };
  pc = c;
  c = c + s;
  digitalWrite(rPin[c], HIGH);
  digitalWrite(rPin[pc], LOW);
  digitalWrite(bPin[3], LOW);
  digitalWrite(bPin[4], HIGH);
  delay(d);
  digitalWrite(bPin[4], LOW);
  digitalWrite(bPin[5], HIGH);
  delay(d);
  if (c>=4 || c <= 0 ){
    s = -s;
  };
  pc = c;
  c = c + s;
  digitalWrite(rPin[c], HIGH);
  digitalWrite(rPin[pc], LOW);
  digitalWrite(bPin[5], LOW);
}

//Beacon single pulse

void pulse(){
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], HIGH);
  }
  delay(50);
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], LOW);
  }
  delay(1000);
}

//beacon triple pulse

void triPulse(){
   for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], HIGH);
  }
  delay(d);
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], LOW);
  }
  delay(d);
   for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], HIGH);
  }
  delay(d);
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], LOW);
  }
  delay(d);
  for(int i = 0; i <= 5; i++){
   digitalWrite(bPin[i], HIGH);
  }
  delay(d);
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], LOW);
  }
  delay(1000);
}

//Beacon double pulse

void dualPulse(){
   for(int i = 0; i <= 5; i++){
   digitalWrite(bPin[i], HIGH);
  }
  delay(d);
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], LOW);
  }
  delay(d);
   for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], HIGH);
  }
  delay(d);
  for(int i = 0; i <= 5; i++){
    digitalWrite(bPin[i], LOW);
  }
  delay(1000);
}


// this is the cycling rainbow for the side strips of NeoPixels. This part is also a pain to explain, and is basically the same as what is in the Strandtest code.

void rainbow(uint8_t wait) {
  uint16_t i, j;
  for(j=0; j<256; j++) {
    for(i=0; i<stripLeft.numPixels(); i++) {
      stripLeft.setPixelColor(i, Wheel1((i+j) & 255));
    }
  }
  for(j=0; j<256; j++) {
    for(i=0; i<stripRight.numPixels(); i++) {
      stripRight.setPixelColor(i, Wheel2((i+j) & 255));
    }
  }
  stripRight.show();   //show the strips simultaneously, not one at a time.
  stripLeft.show();
  delay(wait);
}

// a rather complex set of ifs for the position of the rainbow on the strip:

uint32_t Wheel1(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return stripLeft.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return stripLeft.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return stripLeft.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
uint32_t Wheel2(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return stripRight.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return stripRight.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return stripRight.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}


// a similar rainbow, but slightly different. 

void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< stripLeft.numPixels(); i++) {
      stripLeft.setPixelColor(i, Wheel1(((i * 256 / stripLeft.numPixels()) + j) & 255));
    }
    for(i=0; i< stripRight.numPixels(); i++) {
      stripRight.setPixelColor(i, Wheel2(((i * 256 / stripRight.numPixels()) + j) & 255));
    }
    stripLeft.show();
    stripRight.show();
    delay(wait);
  }
}


void setup() {
  for (count=0;count<6;count++) {  //set the LEDs as outputs
    pinMode(rPin[count], OUTPUT);
  }
  for (count=0;count<6;count++) {
    pinMode(bPin[count], OUTPUT);
  }
  stripLeft.begin();   // initialize all the strips
  stripRight.begin();
  stripLeft.show();
  stripRight.show();
  matrix.begin();              //init the matrix
  matrix.setTextWrap(false);   // makes text scroll nicely
  matrix.setBrightness(40);       // more brightness = more amps needed, and it makes it painful to read, so we keep it relatively low
  matrix.setTextColor(colors[0]);  //set the color
}

void loop() {
  getModes();
  while (mode == 0){
    triPulse();   // change this if you want dual or single pulse
    getMode();
  };
 while (mode == 2){
   rainbowCycle(10);  // you can change this for the other rainbow or any other animation you want (provided you add the code for it)
   getModes();
 };
 while (mode == 3){
   beacon();             // not much to change here
   getModes();
 };
 while (mode == 1){
   matrix.setTextWrap(false);  //just to make sure...
    matrix.setTextSize(1);    // with a bigger matrix, a larger size might be desirable. 1 is perfect for an 8 pixel tall matrix, as the largest letters are exactly 8 pixels tall.
    matrix.setRotation(2);   // orientation and direction of the text scrolling. here it is set from front to back (on my robot), but you can change it if you like.
  matrix.fillScreen(0);
  matrix.setCursor(x, 0);
  matrix.print(F("<Warning: Fart Zone>")); // I was bored. And I ate too many beans. So why not? You will probably want to change the message anyway.
  if(--x < -144) {  // change '144' to a smaller multiple of 12 if you have a shorter message, and change it to a larger multiple of 12 for longer messages. not sure why, but it likes 12s.
    x = matrix.width();
    if(++pass >= 7) pass = 0;
    matrix.setTextColor(colors[pass]);  //change the color each time through. 
  }
  matrix.show();
  delay(55);     // make this smaller to increase scroll speed, and larger to decrease scroll speed. 55 gives a good speed with not too much 'jerkiness' in pixel transitions
  getModes();
 };  
}

Step 10: Testing Everything

So now, you should have read and/or uploaded all of the code to the appropriate boards. Now we need to test it.

Charge up your batteries, get out your goggles, it's time to get this thing rollin'!

Step 1: Power!

Insert the batteries into the battery boxes and power on the Mega with the portable USB power bank.

A display should begin running at this point.

Step 2: Modes

Press the three buttons and the joystick to cycle through modes.

If you can only get some modes to work or it jitters between modes, ensure the Uno has enough power. Check to ensure the wires are in their correct places.

Switch around the values in the Uno code if nothing else works.

Step 3: Driving

Using the joystick, test the drive methods.

If it moves the wrong direction, flip the wires around on the motor(s).

Adjust the motor speeds if it moves too fast or too slow. If you have the speed all the way up, and it still moves extremely slow, try new batteries and ensure the wires are correctly placed.

If it becomes unresponsive, or doesn't stop moving, catch it and hold it still, holding the receiver close to the transmitter, in direct line of sight, until it responds. Alternatively, reset the Uno. This is a problem I am still working on, and I will post updates as I fix it.

Step 11: Results, Potential Upgrades, Lessons Learned, and Afterthoughts

Results:

Overall, I'd call this project a success. It took me a few months to complete due to technical issues, other occupations and sideprojects I was conducting in the meantime. There are still a few issues, though.

Potential Upgrades:

As far as the displays go, the NeoPixels take up a huge amount of memory to run, especially if you want a proper image or animation. A dedicated board such as the Colorduino or the Rainbowduino would probably be better suited to run the Matrix, but as I have neither I decided to simply use the Mega.

The R/C system is the biggest candidate for improvement, as it is currently spotty at best. I am working on 433 Mhz version, but as I said earlier, work is slow. Updates will be posted as I finish them.

Lessons Learned:

NeoPixels are finicky things, especially to test and solder. Research would have been better conducted before rather than after, something I shall remember in days to come.

Wiring is best done with power disconnected, something I discovered after my first receiver went up in metaphorical smoke.

Afterthoughts:

This project would have been better with more experience on my part. My lack of coding expertise has led to some shortcomings in function, but overall the result was acceptable.

In lieu of this, I challenge you to improve this project, to make it better, to improve upon it in every way.

These are the Instructables of Dangerously Explosive, his lifelong mission "to boldly build what you want to build, and more."

You can find the rest of my projects here.

Share

    Recommendations

    • Make it Move Contest

      Make it Move Contest
    • Oil Contest

      Oil Contest
    • Woodworking Contest

      Woodworking Contest
    user

    We have a be nice policy.
    Please be positive and constructive.

    Tips

    Questions

    2 Comments

    Great stuff! Very entertaining, and very thorough.

    1 reply