Creating an LED Mohawk for Misty (Part 2)

All the details: Coding and testing

mohawk
mohawk
Share on facebook
Share on twitter
Share on linkedin
Share on reddit
Share on email

Welcome back! In Part 1, we:

  • scoped our project to use NeoPixels and Misty’s Arduino Backpack
  • used the Misty II CAD library to design a nicely fitting piece of headgear
  • 3D printed and constructed the mohawk

What’s left? Well, in Part 2, we write some simple code to animate the NeoPixels. If you’re like me, you want your LEDs to move and change, so the firmware is where I really start having fun. This is where the blob of plastic and wires I have on my desk starts coming to life and behaving as I’ve pictured in my head. I can play around with the features of the project I’m building and let my creative side take the reigns.

Starting simple, with a quick test

To begin, I just want to get the LEDs working. After all, maybe the plastic walls are too thick and need to be thinned out, but I won’t know until I get the mohawk lit up.

I’m using the official Arduino™ IDE for my project, which does the work of setting up the low-level Arduino hardware. Because the IDE sets up all the low-level hardware, the only two libraries I need are the Misty BackPack library, and the Adafruit® NeoPixel library I’m using to run the LEDs. I include those, create an instance of each, and then the fun begins!

By the way, Adafruit produces an amazing tutorial on NeoPixels and has a fully functioning NeoPixel Arduino library, so there’s no need for me to re-cover that material here. If you’ve never used NeoPixels before, or need to brush up, I’d strongly suggest going to their tutorial and covering the material again. I’m only using four of the basic functions in that library: begin()setPixelColor()Color(), and show().

Also, just in case you’ve not used Arduino before, Arduino sketches have setup() and loop() functions as default. In my Arduino loop() function I’ll do two things. First, I’ll determine whether there are any commands coming from the robot. Second, I’ll control the LEDs.

For my test run, I write a for loop, with one pass through the loop for each NeoPixel, so in this case 11. In each iteration of the loop, I set the color for that LED by using the NeoPixel setPixelColor() function. For now I’m going to set the color as full-strength blue — no red or green.

Once I have the colors set, I end the for loop and call show(). The NeoPixel show() command is the function that actually sends the signal out to the strip, and it’s often forgotten by people, including myself. If your strip doesn’t turn on, the first thing you want to check is that you’re calling begin() and show().

So, right now the code looks like this:

#include <Adafruit_NeoPixel.h>
// I chose pin 7 for the signal wire, but any GPIO pin would do
#define PIN 7
// There are 11 NeoPixels on my strip
#define NUMPIXELS 11
// I defined the first and second parameters above
// The third and fourth parameters are standard for recent strips 
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// I set the light color to full-strength blue for this test pass
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 255;
void setup() {
  // Put your setup code here, to run once
  // Always remember to call the NeoPixel begin method
  strip.begin();
  // Looping through the NeoPixels one at a time to set their color
  for(int ii = 0; ii < NUMPIXELS; ++ii)
  {
    strip.setPixelColor(ii, strip.Color(red, green, blue));
  }
  // Now that all the NeoPixels' colors are set, light them up!
  strip.show();
}
void loop() {
  // Put your main code here, to run repeatedly
}

I upload the program (selecting the board type and COM port for the Arduino) onto the board, and boom-batta-bing, the LEDs are all blue! And there is enough light coming through the plastic that I don’t feel the need to redesign the mohawk.

The mohawk is hooked into Misty’s Arduino Backpack, and the NeoPixels look plenty bright!

From here I can do a lot of creative effects like rotating through colors, or having the front set to one color and the back set to another.

Getting fancy with it

Testing complete, I want to create functions for three different display options:

  1. single_color: Sets the entire mohawk as a single static color.
  2. three_color: Sets each spike of the mohawk as its own color: red, green, or blue.
  3. fade_color: Sets the mohawk all as a single color to start, then fades (at a speed I set) through all the colors of the rainbow.

To get all this animation and movement in my mohawk, I’ll use the Arduino loop() function to perform checks against a timer. To begin, I simply want the loop to call one of my functions to update the LEDs if enough time has elapsed.

#include <Adafruit_NeoPixel.h>
// NeoPixel variables
#define PIN 7
#define NUMPIXELS 11
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// My variables
uint8_t neopixel_state;
uint32_t neopixel_last_change_time = 0;
uint16_t neopixel_delta_change_time = 20;
// My function prototypes for controlling the NeoPixels
void single_color(uint8_t red, uint8_t green, uint8_t blue);
void three_color(void);
void fade_color(void);
void setup() {
  // Always remember to call the NeoPixel begin method
  strip.begin();
}
void loop() {
  // Check to see if it's time to update the LEDs again
  if( ( millis() — neopixel_last_change_time ) > neopixel_delta_change_time )
  {
    // If it's time, run one of my display functions
    neopixel_last_change_time = millis();
    fade_color();
  }
}

Cool. Next I’ll use the neopixel_state variable I created and set things up to switch between all three of my color control functions in the loop. I’ll use a switch statement for the state machine, but you could use a series of ifstatements, if you prefer.

void loop() {
  // Check to see if it's time to update the LEDs again
  if ( ( millis() — neopixel_last_change_time ) > neopixel_delta_change_time )
  {
    // If it's time, switch among the display functions
    neopixel_last_change_time = millis();
    switch (neopixel_state)
    {
      case 0:
        fade_color();
        break;
      case 1:
        three_color();
        break;
      case 2:
        single_color(bp_red, bp_green, bp_blue);
        break;
      default:
        single_color(255, 0, 0);
        break;
    }
  }
}

Notice I created 3 new variables: bp_redbp_green, and bp_blue. These will be the colors that get sent into the backpack from the robot. I also want neopixel_state to be sent in from the backpack, as well as neopixel_delta_change_time, which controls how fast the fading of the colors happens. Let’s discuss how these variables make it down from Misty to the backpack.

Most of the backpack communications happen in a library I’m writing for the backpack: Misty_BackPack. This library handles all the overhead of the communication between the Arduino board and the robot and provides easy access to the data that gets sent down from the head. There are 8 bytes available in each communication packet, and you can structure them however you want. In this case, I’ll set them up in the following order:

0: neopixel_state
1: neopixel_delta_change_time
2: bp_red
3: bp_green
4: bp_blue
5: unused
6: unused
7: unused

Using the Misty BackPack library is as simple as using the NeoPixel library. Include the library at the top of the sketch and create an instance of it.

#include <Adafruit_NeoPixel.h>
#include <Misty_BackPack.h>
// Misty BackPack variables
Misty_BackPack backpack = Misty_BackPack();
// NeoPixel variables...

Then, in the Arduino setup() function, I call the BackPack begin() method, as well as the NeoPixel begin() method.

void setup() {
  // Call the NeoPixel begin method and the BackPack begin method
  strip.begin();
  backpack.begin();
}

And in the loop() function, I write an if statement that includes the BackPack receive() method. The receive() method returns true when new valid data is available, and false otherwise.

void loop() {
  // If there's valid new backpack data, get it
  if( (backpack.receive() )
  {
    neopixel_state = backpack.get_data(0);
    neopixel_delta_change_time = backpack.get_data(1);
    bp_red = backpack.get_data(2);
    bp_green = backpack.get_data(3);
    bp_blue = backpack.get_data(4);
  }
  // Check to see if it's time to update the LEDs again...

Notice that inside the if statement, I’m using the get_data() method to pull specific data into my NeoPixel variables. With any changes to those variables, the NeoPixel code in the loop automatically updates at the next change interval to reflect the changes in the incoming data.

With the logic complete, I should have a fully functioning mohawk. (You can see the full sample code at the bottom of this post.)

Test, test, and test again

One last test. I exercise the Arduino backpack’s control of the mohawk by sending a command from Misty’s API Explorer to the backpack. (I haven’t yet written a skill that runs on Misty to send data and exercise the mohawk and my Arduino sketch.)

I set the state (first byte) as 0 so that the case for the fade_color() function is triggered, and the mohawk will then fade through its colors.

Sending data to the backpack with Misty’s API Explorer

And voila, it works!!

Misty demoing fade_color().

So, this all demonstrates how Misty and the backpack can send data to an accessory, like the mohawk. But an accessory can also send data to the backpack and to Misty. An example of this is if I were to attach an external sensor to Misty that she doesn’t have natively. In the screenshot above of the API Explorer, this sensor data would appear in the text boxes on the right side of the screen. I’ll be discussing this flow in future blog posts.

The Arduino backpack gives you a LOT of options for expanding Misty’s capabilities. Thermal cameras, environment monitoring, actuators for functional arms, trailers, and wearable accessories are just some of the examples of things that can be added to Misty with your creativity. We’re excited to see what you’ll build!

Last but not least, testing the three_color() function.

Here’s the complete program that we built in this post:

#include <Adafruit_NeoPixel.h>
#include <Misty_BackPack.h>
// Misty BackPack variables
Misty_BackPack backpack = Misty_BackPack();
// NeoPixel variables
// I chose pin 7 for the signal wire, but any GPIO pin would do.
#define PIN  7
// There are 11 NeoPixels on my strip.
#define NUMPIXELS  11
// Construct an instance of the NeoPixel strip class.
// The 3rd & 4th parameters are standard for recent NeoPixel strips.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
// My variables
uint8_t neopixel_state;
uint32_t neopixel_last_change_time = 0;
uint16_t neopixel_delta_change_time = 20;
uint8_t bp_red = 0;
uint8_t bp_green = 0;
uint8_t bp_blue = 255;
// My function prototypes for controlling the NeoPixels
void single_color(uint8_t red, uint8_t green, uint8_t blue);
void three_color(void);
void fade_color(void);
void setup() {
  // Put your setup code here, to run once.
  // Call the NeoPixel begin method and the BackPack begin method.
  strip.begin();
  backpack.begin();
}
void loop() {
  // Put your main code here, to run repeatedly.
  // If there's valid new backpack data, get it.
  if ( backpack.receive() ) // True if a new packet is received.
  {
    neopixel_state = backpack.get_data(0);
    neopixel_delta_change_time = backpack.get_data(1);
    bp_red = backpack.get_data(2);
    bp_green = backpack.get_data(3);
    bp_blue = backpack.get_data(4);
  }
  // Check to see if it's time to update the LEDs again.  
  if ( ( millis() - neopixel_last_change_time ) > neopixel_delta_change_time)
  {
    // If it's time, switch among the display functions.
    neopixel_last_change_time = millis();
    switch (neopixel_state)
    {
      case 0:
        fade_color();
        break;
      case 1:
        three_color();
        break;
      case 2:
        single_color(bp_red, bp_green, bp_blue);
        break;
      default:
        single_color(255, 0, 0);
        break;
    }
  }
}
// Set the mohawk as a single color to start,
// then fade through all the colors of the rainbow.
void fade_color(void)
{
  static uint8_t state = 0;
  static uint8_t red = 0;
  static uint8_t green = 0;
  static uint8_t blue = 0;
  switch (state)
  {
    case 0:
      blue = 0;
      ++green;
      if (--red == 0)
      {
        state = 1;
      }
      break;
    case 1:
      red = 0;
      ++blue;
      if (--green == 0)
      {
        state = 2;
      }
      break;
    case 2:
      green = 0;
      ++red;
      if (--blue == 0)
      {
        state = 0;
      }
      break;
    default:
      red = 255;
      blue = 0;
      green = 0;
      state = 0;
      break;
  }
  for (int ii = 0; ii < NUMPIXELS; ++ii)
  {
    strip.setPixelColor(ii, strip.Color(red, green, blue));
  }
  strip.show();
}
// Set the entire mohawk as a single static color.
void single_color(uint8_t red, uint8_t green, uint8_t blue)
{
  for (int ii = 0; ii < NUMPIXELS; ++ii)
  {
    strip.setPixelColor(ii, strip.Color(red, green, blue));
  }
  strip.show();
}
// Set each spike as its own color: red, green, or blue.
void three_color(void)
{
  uint32_t red = strip.Color(255, 0, 0);
  uint32_t green = strip.Color(0, 255, 0);
  uint32_t blue = strip.Color(0, 0, 255);
  strip.setPixelColor(0, red);
  strip.setPixelColor(1, red);
  strip.setPixelColor(2, red);
  strip.setPixelColor(3, red);
  strip.setPixelColor(4, green);
  strip.setPixelColor(5, green);
  strip.setPixelColor(6, green);
  strip.setPixelColor(7, blue);
  strip.setPixelColor(8, blue);
  strip.setPixelColor(9, red);
  strip.setPixelColor(10, green);
  strip.show();
}

Leave a comment

Your email address will not be published. Required fields are marked *

Authentic, Relevant Robot News
Join for industry highlights and insider views
Featured Posts
Categories
Archives
Archives

Free Misty Robot Giveaway for Developers

Enter to win a Misty prototype and then receive a trade-in for a brand new Misty II during the first wave of shipments!