XRAD'S MANDALORIAN GRAV CHARGE w/Trinket M0

Adafruit's tiny microcontroller platform. Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
XRAD
 
Posts: 753
Joined: Sat Nov 19, 2016 3:28 pm

XRAD'S MANDALORIAN GRAV CHARGE w/Trinket M0

Post by XRAD »

Well, I thought it would be cool to try to squeeze all these parts into a tiny case...it's the 3d puzzle and the code puzzle I enjoy so much. Bought some metal grav charges off etsy (link in code). they are super well made. Unfortunately, the lens that came with the charges was too big, hence the use of the siemens lens (link in code). You have to pop the lens off the bulb holder. Don;t worry, it's really strong. This gave me about 5-7 more mm in the case. Had to 3D print a stand for the switch, and a new lens holder...but just those two parts. I am still contemplating whether to drill the base or the side for the piezo ....probably the side..just more room for the touch charger pads and magnet on bottom of charge case...and better sound! code below...enjoy!

Hardware:
adafruit trinket M0
adafruit TDK piezo PS1240
adafruit Jewel
Grav charge models from etsy: https://www.etsy.com/listing/1247432778
100maH Lipo..the tiny one!
pololu mini push button power switch, LV
Siemens 3SU10016AA200AA0, Indicator Light, Red, Smooth Lens (just using the red lens)

short vid: https://www.youtube.com/watch?v=qzZ6tX6nk1A

Code: Select all

/* XRAD'S Mandalorian Grav Charge  9/19/2022
 * Hardware: adafruit trinket M0
 * adafruit TDK piezo PS1240
 * adafruit Jewel
 * Grav charge models from: https://www.etsy.com/listing/1247432778
 * 100maH Lipo..the tiny one!
 * pololu mini on off switch
 * Siemens 3SU10016AA200AA0, Indicator Light, Red, Smooth Lens (just using the red lens)
 * my youtube vid: https://www.youtube.com/watch?v=qzZ6tX6nk1A
 * 
 * had to create a bit of non-blocking code to run the pixels and piezo at same time. 
 * I'm sure there is a better way, but this was straight-forward. feel free to use
 * or modify as you like!
  */


#include <Adafruit_NeoPixel.h> // include the Neopixel Library in this Sketch

#define LED_PIN 2 // Data out to strip

#define LED_COUNT 7 // how many pixels in entire strip

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN);//num pixels , pin

//pixel variables
int PXL1[] = {0, 1, 2, 3, 4, 5, 6};
int pixelRingPos = 1;

//piezo variables
const int BuzzerPin =  3;
int BuzzerPinState = LOW;
unsigned int Tone = 3500;//initial low tone
int toneCount = 0;

//piezo main delay
int previousMillis2 = 0;
int interval2 = 100;//interval no-tone gap

//piezo mini delay
unsigned long previousMillis = 0;
int interval = 50; // interval at which to sound

//leds
unsigned long previousMillis1;
int interval1 = 100;
int ledState = LOW;

void Larson() {//modified Larson scanner!
  int pos = 0, dir = 1; // initial position, initial direction of "eye"
  for (int i = 0; i < 200; i++) {
    int j;
    strip.setPixelColor(pos - 3, 0x100000); // Dark red
    strip.setPixelColor(pos - 2, 0x100000); // Dark red
    strip.setPixelColor(pos - 1, 0x800000); // Medium red
    strip.setPixelColor(pos    , 0xFFFFFF); // Center pixel is brightest, the 'eye'
    strip.setPixelColor(pos + 1, 0x800000); // Medium red
    strip.setPixelColor(pos + 2, 0x100000); // Dark red
    strip.setPixelColor(pos + 3, 0x100000); // Dark red
    strip.show();
    delay(30);

    for (j = -2; j <= 2; j++)
      strip.setPixelColor(pos + j, 0);
    pos += dir;
    if (pos < 0) {
      pos = random(1 - 6);
      dir = -dir;
    } else if (pos >= strip.numPixels()) {
      pos = random(1 - 6);
      dir = -dir;
    }
  }
  strip.clear();
  strip.show();
}


void setup() {
  randomSeed(analogRead(20));
  pinMode(BuzzerPin, OUTPUT);
  strip.setBrightness(150);
  strip.begin();
  strip.clear();
  strip.show();
}

void loop() {

  unsigned long currentMillis = millis();

  //piezo function
  if (currentMillis - previousMillis2 >= interval2) {
    previousMillis2 = currentMillis;
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (BuzzerPinState == LOW) {
        BuzzerPinState = HIGH;
        //Serial.println(Tone);
        tone(BuzzerPin, Tone);
        toneCount++;
        //Serial.println(toneCount);
      } else {
        BuzzerPinState = LOW;
        noTone(BuzzerPin);
      }
    }
  }


  //pixel function
  if (currentMillis - previousMillis1 >= interval1) {
    previousMillis1 = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(255, 0, 0));
      strip.show();
    } else {
      ledState = LOW;
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(0, 0, 0));
      strip.show();
      pixelRingPos++;
      if (pixelRingPos > 6) {
        pixelRingPos = 1;
      }
    }
  }


  if (toneCount >= 4) {
    toneCount = 0;
    noTone(BuzzerPin);
    Tone = Tone + 100;
    if (Tone >= 4700) {
      Tone = 4700;
      tone(BuzzerPin, Tone);
      delay(1500);
      noTone(BuzzerPin);
      Larson();
      pixelRingPos = 1;
      Tone = 3500;
      //insert device state change here, and signal to pololu to OFF
      delay(5000);
    }
  }
}
small grav.JPG
small grav.JPG (81.1 KiB) Viewed 264 times

User avatar
XRAD
 
Posts: 753
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S MANDALORIAN GRAV CHARGE w/Trinket M0

Post by XRAD »

so the above code kept crashing after running a while. I think it was a timer conflict. So I rewrote it using multiple millis() timers. It is waaaayyy better now. Check it out below.

NOTE: although using arduino 'tone(buzzer)' is non blocking, and can have two or three arguments (third for length of play), in order to not use 'delay' to maintain the tone play time, you have to use millis() timer or another way. The millis() time to be 'on' must be longer than the tone play time. Subtract tone play time from your millis() timer to get the 'off' time. So for example, if I use tone(buzzer,4500,50)..this means that the buzzer pin will play 4500 hz for 50 milliseconds. If my timer is 100 milliseconds, then the off time is 50 milliseconds...etc...

new vid:
https://www.youtube.com/watch?v=vbc7Ajk7PfQ

new code:

Code: Select all

/* XRAD'S Mandalorian Grav Charge  9/19/2022
   Hardware: adafruit trinket M0
   adafruit TDK piezo PS1240
   adafruit Jewel
   Grav charge models from: https://www.etsy.com/listing/1247432778
   100maH Lipo..the tiny one!
   pololu mini on off switch
   Siemens 3SU10016AA200AA0, Indicator Light, Red, Smooth Lens (just using the red lens)
   my youtube vid: https://www.youtube.com/watch?v=qzZ6tX6nk1A

   had to create a bit of non-blocking code to run the pixels and piezo at same time.
   I'm sure there is a better way, but this was straight-forward. feel free to use
   or modify as you like!
*/


#include <Adafruit_NeoPixel.h> // include the Neopixel Library in this Sketch

#define LED_PIN 2 // Data out to strip
#define LED_COUNT 7 // how many pixels in entire strip

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN);//num pixels , pin


//piezo mini beep delay
int buzzer = 3;
int piezoTime = 100;//mini beep interval (well, minus the buzzer play time!)
unsigned long piezoTimer;
int timer = 0;
int freq = 3500;

//piezo main delay variables
unsigned long previousMillis2;
int piezoOffTime = 1000;  //interval no-tone gap (well, minus the buzzer play time!)
bool offTimerFlag = false;

//neopixel variables
unsigned long previousMillis1;
int intervalPixel = 100;// time between pixel position change
int pixelState = LOW;
int PXL1[] = {0, 1, 2, 3, 4, 5, 6};//array of ring pixels, 0 is center pixel
int pixelRingPos = 1;//1st position on outside of ring

void Larson() {//my modified Larson scanner!
  int pos = 0, dir = 1; // initial position, initial direction of "eye"
  for (int i = 0; i < 200; i++) {
    int j;
    strip.setPixelColor(pos - 3, 0x100000); // Dark red
    strip.setPixelColor(pos - 2, 0x100000); // Dark red
    strip.setPixelColor(pos - 1, 0x800000); // Medium red
    strip.setPixelColor(pos    , 0xFFFFFF); // Center pixel is brightest, the 'eye'
    strip.setPixelColor(pos + 1, 0x800000); // Medium red
    strip.setPixelColor(pos + 2, 0x100000); // Dark red
    strip.setPixelColor(pos + 3, 0x100000); // Dark red
    strip.show();

    for (j = -2; j <= 2; j++)
      strip.setPixelColor(pos + j, 0);
    pos += dir;
    if (pos < 0) {
      pos = random(1, 7);
      dir = -dir;
    } else if (pos >= strip.numPixels()) {
      pos = random(1, 7);
      dir = -dir;
    }
    delay(30);//delay pixel display a bit
  }
  strip.clear();
  strip.show();
}


void setup() {
  // Serial.begin(9600);
  pinMode(buzzer, OUTPUT);
  randomSeed(analogRead(20));//for the larson scanner random
  strip.setBrightness(150);//save my wee battery!
  strip.begin();
  strip.clear();
  strip.show();
  delay(100);//short power-up delay
  piezoTimer = millis();//don't put a delay after these timers begin!
  previousMillis2 = millis();
  previousMillis1 = millis();
}


void loop() {

  //piezo
  if ((offTimerFlag == true) && (millis() - previousMillis2 >= piezoOffTime)) {
    previousMillis2 = millis();
    offTimerFlag = false;
  }
  if ((offTimerFlag == false) && (millis() - piezoTimer >= piezoTime)) {
    tone(buzzer, freq, 60);
    //Serial.print("timer: ");
    //Serial.println(timer);
    piezoTimer = millis();
    timer++;
    if (timer > 3) {
      freq = freq + 100;
      timer = 0;
      offTimerFlag = true;
    }
    if (freq >= 4500) {
      strip.clear();
      strip.show();
      for (int x = 0; x < strip.numPixels(); x++) {
        strip.setPixelColor(x, strip.Color(255, 0, 0));
        strip.show();
      }
      tone(buzzer, 4500);
      delay(1500);//hold buzzer tone for this long
      noTone(buzzer);
      strip.clear();
      strip.show();
      delay(100);
      Larson();
      delay(5000);//temporary
      //insert device state change here, and signal to pololu to OFF
      freq = 3500;
      pixelRingPos = 1;
      timer = 0;
    }
  }


  //pixel
  if (millis() - previousMillis1 >= intervalPixel) {
    previousMillis1 = millis();
    if (pixelState == LOW) {
      pixelState = HIGH;
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(255, 0, 0));
      strip.show();
    } else {
      pixelState = LOW;
      strip.setPixelColor(PXL1[pixelRingPos], strip.Color(0, 0, 0));
      strip.show();
      pixelRingPos++;
      if (pixelRingPos > 6) {
        pixelRingPos = 1;
      }
    }
  }
}

User avatar
XRAD
 
Posts: 753
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S MANDALORIAN GRAV CHARGE w/Trinket M0

Post by XRAD »

Hey hey...I finally finished a project. Managed to squeeze all the components (including 100mAh lipo) into case. Added a charger POS pin at base. The entire case is the charger NEG. I will design a charging base next. There is a strong magnet on the base as well. trinket pin OUT triggers the pololu switch to OFF. Uses something tiny like ~.01 micro Amps in OFF state....

See the final grav charge vid here:
https://www.youtube.com/watch?v=T48CVYbuTmo


BASE MINI.JPG
BASE MINI.JPG (29.85 KiB) Viewed 197 times
GRV FINAL PIC.JPG
GRV FINAL PIC.JPG (32.35 KiB) Viewed 197 times

User avatar
XRAD
 
Posts: 753
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S MANDALORIAN GRAV CHARGE w/Trinket M0

Post by XRAD »

Finished printing and testing the charger base. Cut up a pen spring (steel) and soldered leads to the springs. 1s USB charger. When the grav charge device is placed into the charger unit receiver, a metal washer in the charger unit attracts the grav charge device magnet against both the side and bottom springs. This design works well.

crgr 1 mini.JPG
crgr 1 mini.JPG (49.2 KiB) Viewed 177 times
crgr 2 mini.JPG
crgr 2 mini.JPG (43.05 KiB) Viewed 177 times
crgr 3 mini.JPG
crgr 3 mini.JPG (61.1 KiB) Viewed 177 times

User avatar
XRAD
 
Posts: 753
Joined: Sat Nov 19, 2016 3:28 pm

Re: XRAD'S MANDALORIAN GRAV CHARGE w/Trinket M0

Post by XRAD »

inside components of grav charge. The pololu switch is loosely sandwiched between the led holder and the trinket holder. To make assembly easier, I use the trinket USB frame as a ground. OK, this project is pretty much done. I have a few more to finish now......

IMG_0857.JPG
IMG_0857.JPG (59.3 KiB) Viewed 174 times
mini explod.JPG
mini explod.JPG (63.24 KiB) Viewed 174 times

Locked
Please be positive and constructive with your questions and comments.

Return to “Trinket ATTiny, Trinket M0”