Introduction: Pulse-Detecting Collar

This is a project utilizing a NeoPixel LED strip to send out constant signals of life (when the detected heartrate is normal). I have it running a rainbow colorwipe animation, but with a few changes to the code, you can customize it however you like!

You'll want to start with the electronics and basic wiring, then proceed to coding. Meshing the material of the collar and the lights will be fairly easy for anyone with a little design experience.

Supplies

Arduino Uno, ATtiny85 (highly recommended), NeoPixel LEDS, a switch (optional), LiPo battery, basic soldering setup, MAX30102 Heartrate sensor, wires for making connections, waterproofing method (I recommend conforming electronics-grade silicone), and a collar. You can make one or hack a premade collar to work.

Step 1: Starting Your Circuit

The first thing you'll want to do is make sure your MAX30102 is working. Solder jumper wires to the VIN, SDA, SCL, and GND. For this project I'm using an Arduino Uno, but most boards should be compatible with the MAX. Connect the wires to the corresponding ports on your Arduino.

NOTE: The MAX30102 has a glaring design flaw. None of the connections on its surface are insulated, and thus pressing your finger against the sensor causes a bunch of tiny shorts. While working out the functionality, I covered everything but the infrared sensor in the middle with electrical tape to keep my skin from making contact with it. You'll want to waterproof the board later.

Install the Sparkfun MAX3010x library. You can download it at GitHub here. Run one of the example programs as you press your finger to the sensor, holding it in place with a rubber band. Consistent pressure is required and the rubber band will dramatically increase the accuracy. If your sensor is working, then you can continue!

Decide how many NeoPixels off the strip you're going to use (this depends also on the length of your collar). For mine, I used ten NeoPixels in a single strip. NeoPixels use three lines; a 5V line in, an information line, and ground. At this point I was starting to streamline the electronics, as they're all running off one 3.8V battery, so I soldered power input and ground lines for the MAX and the NeoPixel strip together.

There's a number of different NeoPixel code libraries you can choose from, but I used this one to test my strip and base my code off of. It's worth researching NeoPixels further for advice on soldering and playing with their code - I spent a fair amount of time just googling what they could do and how to use them in different ways before including them in this project.

Step 2: Creating Your Code

The code for this is a little tricky - the preview image for this step was one of the many attempts at making a working program, syncing up a rainbow colorwipe effect with normal heartrate detection. After a lot of correspondence with a more experienced programmer, I was finally able to get something that worked.

This code is built off the example code written by Sparkfun.

The NeoPixel definition before the setup in this code include (10, 1). These numbers refer to the number of pixels on the strip, and the pin where we're connecting the data line. Since we're transferring this to a ATtiny85, we're putting the pin as 1, but the default pin on the UNO for testing the pixels is 6. If you use more or less pixels than I did, change the 10 to your own number.

#include <Wire.h>
#include "MAX30105.h"
#include <Adafruit_NeoPixel.h>
#include "heartRate.h"

MAX30105 particleSensor;
Adafruit_NeoPixel strip(10, 1, NEO_GRB + NEO_KHZ800);
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred

float beatsPerMinute;
int beatAvg;
int pixelHue;
void setup()
{


  // Initialize sensor
  particleSensor.begin(Wire, I2C_SPEED_FAST); //Use default I2C port, 400kHz speed
  particleSensor.setup(); //Configure sensor with default settings
  particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
}

void loop()
{
  long irValue = particleSensor.getIR();
  if (checkForBeat(irValue) == true)
  {
    //We sensed a beat!
    long delta = millis() - lastBeat;
    lastBeat = millis();

    beatsPerMinute = 60 / (delta / 1000.0);

    if (beatsPerMinute < 255 && beatsPerMinute > 20)
    {
      rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
      rateSpot %= RATE_SIZE; //Wrap variable

      //Take average of readings
      beatAvg = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        beatAvg += rates[x];
      beatAvg /= RATE_SIZE;

      if (beatAvg < 80 && beatAvg > 50)
      {
        colorWipe(100);
        Clear();
      }
    }
  }





}
void Clear()
{
  for (int i = 0; i < strip.numPixels(); i++)
  {
    strip.setPixelColor(i, (0, 0, 0));       //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
  }
}

void colorWipe(int wait) {
  for (int i = 0; i < strip.numPixels(); i++)
  {
    for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256)
    {
      pixelHue = firstPixelHue + (i * 67000L / strip.numPixels());
    }


    strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}



Step 3: Finishing Your Circuit

Now that you have your code, you can transfer it over to your ATtiny85. I'm not going to include a tutorial for this, but the code should fit on the Tiny just fine and there's plenty of other tutorials online!

With the code on your tiny85, you can now finish your circuit. Solder wires to the positive and ground for the Tiny board and connect them to the positive and ground lines for your other two pieces of hardware. Connect your SDA line off the MAX30102 to pin 0, the NeoPixel data line to pin 1, and the MAX SCL line to pin 2 on the Tiny. You should now have a completed circuit that only needs to be connected to a power source, and I used a 3.8 volt LiPo battery. I also added a linear 335Ω resistor on the data line for the NeoPixels as well. This is recommended just to stabilize the flow.

I needed a place to house the ATtiny58 on the collar, so that I could still access it if anything broke. I have a tutorial here on how I built a small resin box to keep the electronics clean.

Attachment of the wires will depend on what kind of battery you're using, but I was using a battery with a mCPX connector. I soldered the female side to the positive and ground lines off our circuit. When the battery is connected, the entire thing should run.

OPTIONAL: For this project I also added a small mechanical switch to save power. This was ridiculously easy to add - I simply soldered it onto the positive line before completing the battery connector. This switch was added to my resin housing for the ATtiny85.

Step 4: Finishing the Collar

With the circuit complete, we can now officially make it wearable!

To start I sewed a small patch in to house the battery, with a hole going out one side to the surface of the fabric. I glued the resin housing box directly to the surface of the collar, facing outward, and ran the power line through the hole. This way the battery could be disconnected for charging.

Mounting the heartrate sensor was easy. Create another tunnel from the surface to the inside of the collar and run the MAX through it, so that the sensor faces inwards and will be pressed against the neck. It will move through the collar a bit like a button so that when it comes out the other side, it holds itself in place. I had waterproofed my circuit with silicone at this point and added some extra fabric around the sensor to make it comfortable.

Finally we can install the NeoPixels. They can remain exposed if you want to do more work on them, but I choose to embed them into the collar by running the strip through the layers of fabric. When it was fully extended, I cut holes where each LED was located and sealed them in place with glue.

At this point you should have a functional, wearable collar that responds to a resting heartrate with a lovely little rainbow light show!