Here's our circuit diagram. You can easily switch in a 3V Trinket in place of one or both Gemmas.
If you have any safety concern about the laser, then substitute in a super bright red 5mm LED and a 50 Ohm resistor. I installed both and put connectors on them to switch back and forth. The LED still looks pretty good.
First up, the servo control. You may want to refer to the Laser Dog Goggles guide as it is based off that project but with a few tweaks:
- The laser has been moved to the other Gemma device. This because we wanted one switch to activate the motor and the other to activate lights.
- I wanted a slower sweep speed. To do this I changed the moveAmount and servoPos variables from int to float, which opens up decimal increments. So I can use a moveAmount of 0.5
- There is some code that makes the servo jump +/- 15 degrees at random. Why? Becuase we thought it looked creepier.
Here's the sketch:
/******************************************************************* SoftServo sketch for Adafruit Trinket. Increments values to change position on the servo (0 = zero degrees, full = 180 degrees) Required library is the Adafruit_SoftServo library available at https://github.com/adafruit/Adafruit_SoftServo The standard Arduino IDE servo library will not work with 8 bit AVR microcontrollers like Trinket and Gemma due to differences in available timer hardware and programming. We simply refresh by piggy-backing on the timer0 millis() counter Required hardware includes an Adafruit Trinket microcontroller a servo motor, and a potentiometer (nominally 1Kohm to 100Kohm As written, this is specifically for the Trinket although it should be Gemma or other boards (Arduino Uno, etc.) with proper pin mappings Trinket: USB+ Gnd Pin #0 Connection: Servo+ - Servo1 *******************************************************************/ #include <Adafruit_SoftServo.h> // SoftwareServo (works on non PWM pins) #define SERVO1PIN 0 // Servo control line (orange) on Trinket Pin #0 int skipCount = 100; //These are variables for the random servo skip int skip = 0; float moveAmount = 0.5; // change this value to change speed of servo float servoPos = 0; // variable for servo position Adafruit_SoftServo myServo1; //create servo object void setup() { // Set up the interrupt that will refresh the servo for us automagically OCR0A = 0xAF; // any number is OK TIMSK |= _BV(OCIE0A); // Turn on the compare interrupt (below!) myServo1.attach(SERVO1PIN); // Attach the servo to pin 0 on Trinket myServo1.write(90); // Tell servo to go to position per quirk delay(15); // Wait 15ms for the servo to reach the position } void loop() { skip = skip + 1; //counter for when the servo will a random jump if (skip == skipCount) { servoPos = servoPos + random (-15,15); if (servoPos < 1) servoPos=1; //this stops the servo from jumping outside its range if (servoPos > 119) servoPos=119; //the servo goes crazy if this happens skip=0; skipCount=random (100,300); //set the next interval for the servo to skip } myServo1.write(servoPos); // tell servo to go to position servoPos = servoPos + moveAmount; // increment servo position (value between 0 and 180) if (servoPos == 0 || servoPos == 120){ moveAmount = -moveAmount; //reverse incrementer at bounds } delay(15); // waits 15ms for the servo to reach the position } // We'll take advantage of the built in millis() timer that goes off // to keep track of time, and refresh the servo every 20 milliseconds // The SIGNAL(TIMER0_COMPA_vect) function is the interrupt that will be // Called by the microcontroller every 2 milliseconds volatile uint8_t counter = 0; SIGNAL(TIMER0_COMPA_vect) { // this gets called every 2 milliseconds counter += 2; // every 20 milliseconds, refresh the servos! if (counter >= 20) { counter = 0; myServo1.refresh(); } }
Now the Neopixels. There's a are three things happening in the sketch:
- D0 is driving the laser/LED which is usually on. But at random intervals will flicker.
- At a set interval (in this case 3 seconds) one of the three pixels is selected at random and set to a random colour within an array. This uses the millis() timer.
- The pixel ring blinks a randomly selected pixel a random duration, picking a random colout from an array.
Yes that's a lot of use of the random() function.
You'll need the NeoPixel library of course.
Here's the sketch to upload to the second Gemma or Trinket:
#include <Adafruit_NeoPixel.h> #define PIN 1 // Parameter 1 = number of pixels in strip // Parameter 2 = pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) Adafruit_NeoPixel pixels = Adafruit_NeoPixel(15, PIN, NEO_GRB); uint32_t colorArray[3] = {0x10002C, 0x001000, 0x000010}; //the colours to use on the pixel ring uint32_t colorArray2[4] = {0x500000, 0x005000, 0x000050, 0x505000}; //the colours to use for the neopixels int howLongToWait = 3000; // Wait this many millis() int lastTimeItHappened = 0; // The clock time in millis() int howLongItsBeen; // A calculated value int led = 0; int flkr = 0; void setup() { pixels.begin(); pinMode(led, OUTPUT); digitalWrite(led, HIGH); } void loop() { uint8_t i; uint16_t d; //pixel ring is on pixels 4-15 i = random(3,15); //select a random pixel on the ring d = random(5, 250); //light it for a random duration pixels.setPixelColor(i, colorArray[random(3)]); pixels.show(); delay(d); pixels.setPixelColor(i, 0); //add some random blinks to the Laser Diode flkr = flkr + 1; if ( flkr >= 80) { //arbitrary number raise/lower to adjust the frquency of blinks digitalWrite(led, LOW); delay (50); digitalWrite(led, HIGH); delay (25); digitalWrite(led, LOW); delay (50); digitalWrite(led, HIGH); flkr = 0; } //millis timer code to cycle random colours to pixels 1-3 howLongItsBeen = millis() - lastTimeItHappened; if ( howLongItsBeen >= howLongToWait ) { pixels.setPixelColor(random(0, 3), colorArray2[random(4)]); pixels.show(); // do it (again) lastTimeItHappened = millis(); } }
Test everything out, modify code if you want to alter the timing or behaviour. If everything checks out you're ready to put it all together.
Page last edited November 19, 2014
Text editor powered by tinymce.