Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: Combining FastLED and Other Functionality Simulataneously; Animatronics

Threaded View

  1. #1
    Junior Member
    Join Date
    May 2020
    Posts
    19

    Combining FastLED and Other Functionality Simulataneously; Animatronics

    Teensy 3.5. Custom PCB (not audio shield). I am an EE Tech I make my own shields.

    OK! The source code below works! My animatronic skull model turns on when I trigger the sensor and the jaw servo maps to the audio output!

    So now I need to integrate some FastLED into the action. How is this done without multi-threading? I am still teaching myself about timing loops and Arduino here so bear with me (or better yet fill me in).

    Thank you!!

    Source Code:
    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #include <PWMServo.h>
    
    // Configuration
    // Connections
    #define SERVO_PIN 10 // Jaw servo
    #define PING_PIN 5 // ping / echo for sonar distance sensor
    #define ECHO_PIN 6
    #define MOSFETPin 9 // mostfet for servo power control
    
    // How long until the ping returns to consider it a "trigger"
    #define  SONAR_THRESHOLD 900 // microseconds.
    // Speed of sound in air is about 343 m/s, so this is about 15 cm (~6 in), or a 30cm round trip.
    // Quick calculators:
    // const SONAR_THRESHOLD (148 * 6) // ~inches
    // const SONAR_THRESHOLD (58 * 15) // ~cm
    
    // Servo range configuration
    #define JAW_OPEN 70
    #define JAW_CLOSED 0
    
    // Length of time for `loop()` to run.  1000/25 Hz (40ms) should be pretty fluid
    #define  SAMPLE_TIME 200  // ms
    
    // Sound file to play when sonar triggers
    #define  SAMPLE_FILE "01.wav"
    
    // Delay playback to compensate for the jaw servo's lag.
    #define SERVO_DELAY 50 // ms
    
    // To play with this, import the below block into https://www.pjrc.com/teensy/gui/
    
    // playSdWav1 will use the built-in sd card slot, assumed to have a fat32 filesystem.
    // If you're using some other way to attach SD, or you'd like to use in-memory or
    // whatever, there are other options.
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioPlaySdWav           playSdWav1;     //xy=329,371
    AudioMixer4              mixer1;         //xy=548,386
    AudioEffectDelay         delay1;         //xy=749,424
    AudioOutputAnalog        dac1;           //xy=951,421
    AudioAnalyzePeak         peak1;          //xy=973,360
    AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
    AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
    AudioConnection          patchCord3(mixer1, delay1);
    AudioConnection          patchCord4(delay1, 0, peak1, 0);
    AudioConnection          patchCord5(delay1, 1, dac1, 0);
    // GUItool: end automatically generated code
    
    #define SDCARD_CS_PIN    BUILTIN_SDCARD
    #define SDCARD_MOSI_PIN  11  // not actually used
    #define SDCARD_SCK_PIN   13
    
    PWMServo jaw;
    
    // Entirely optional.  For stable sample management.  `elapsedMillis` is a teensy type that
    // automatically counts up, so it's useful for making sure if you want 25Hz, you _get_ 25Hz.
    elapsedMillis timing;
    
    int ping() {
      digitalWrite(PING_PIN, LOW);
      delayMicroseconds(2);
      digitalWrite(PING_PIN, HIGH);
      delayMicroseconds(10);
      digitalWrite(PING_PIN, LOW);
      if (pulseIn(ECHO_PIN, HIGH, SONAR_THRESHOLD) != 0) {
        return HIGH;
      }
      return LOW;
    }
    
    
    uint8_t mosfet_state = LOW;
    void set_mosfet(uint8_t state) {
      if (state != mosfet_state) {
        Serial.print("Setting MOSFET to ");
        Serial.println(state == LOW ? "LOW" : "HIGH");
        mosfet_state = state;
        digitalWrite(MOSFETPin, mosfet_state);
      }
    }
    
    
    void setup() {
      Serial.begin(9600);
      Serial.println("initializing audio memory");
     
      // Set up audio memory.  You need at least 1 block for each 2.9 ms of delay, plus
      // a minimum of 8 blocks for the player. 
      AudioMemory((int) (ceil(SERVO_DELAY / 2.9) + 8));
      Serial.println("initializing pins");
      jaw.attach(SERVO_PIN);
      pinMode(PING_PIN, OUTPUT);
      pinMode(ECHO_PIN, INPUT);
      pinMode(MOSFETPin, OUTPUT);
      delay1.delay(0, 0);    
      delay1.delay(1, SERVO_DELAY);
      delay1.disable(2);
      delay1.disable(3);
      delay1.disable(4);
      delay1.disable(5);
      delay1.disable(6);
      delay1.disable(7);
      
      mixer1.gain(0, 1.0);
      mixer1.gain(1, 1.0);
      mixer1.gain(2, 0);
      mixer1.gain(3, 0);
      
      Serial.println("initializing SD access");
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here, but print a message repetitively
        while (1) {
          Serial.println(SD.begin(SDCARD_CS_PIN));
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
    }
    
    void loop_state_waiting() {
      if (mosfet_state == HIGH) {
        Serial.println("playback ended; returning to sleep.");
      }
      set_mosfet(LOW);
      if (ping() == HIGH) {
        Serial.println("sonar ping!  Starting sound/animation.");
        set_mosfet(HIGH);
        playSdWav1.play(SAMPLE_FILE);
        delay(5);
      }
    }
    
    void loop_state_playing() {
      if (peak1.available()) {
        float level = peak1.readPeakToPeak();
        int new_servo_pos = (int) (level * (JAW_OPEN - JAW_CLOSED) / 2.0 + JAW_CLOSED);
        Serial.print("Level: ");
        Serial.print(level);
        Serial.print("; servo: ");
        Serial.println(new_servo_pos);
        jaw.write(new_servo_pos);
      }
    }
    
    void loop() {
      // resets the counter
      timing = 0;
      if (!playSdWav1.isPlaying()) {
        loop_state_waiting();
      } else {  
        loop_state_playing();
      }
      // Only delay for the remaining time in the sample.
      delay(SAMPLE_TIME - timing);
    }

    Want to include:
    Code:
    //Skull Eyes
    
    #define FRAMES_PER_SECOND 8
    #include <FastLED.h>
    bool gReverseDirection = false;
    
    #define NUM_LEDS_PER_STRIP 10
    CRGB leds[NUM_LEDS_PER_STRIP];
    
    // For mirroring strips, all the "special" stuff happens just in setup.  We
    // just addLeds multiple times, once for each strip
    void setup() {
      // tell FastLED there's 60 NEOPIXEL leds on pin 4
      FastLED.addLeds<NEOPIXEL, 2>(leds, NUM_LEDS_PER_STRIP);
    
      // tell FastLED there's 60 NEOPIXEL leds on pin 5
      FastLED.addLeds<NEOPIXEL, 3>(leds, NUM_LEDS_PER_STRIP);
    
     
    }
    
    void loop()
    {
      // Add entropy to random number generator; we use a lot of it.
      // random16_add_entropy( random());
    
      Fire2012(); // run simulation frame
      
      FastLED.show(); // display this frame
      FastLED.delay(1000 / FRAMES_PER_SECOND);
    }
    
    
    #define COOLING  55
    
    // SPARKING: What chance (out of 255) is there that a new spark will be lit?
    // Higher chance = more roaring fire.  Lower chance = more flickery fire.
    // Default 120, suggested range 50-200.
    #define SPARKING 120
    
    
    void Fire2012()
    {
    // Array of temperature readings at each simulation cell
      static byte heat[NUM_LEDS_PER_STRIP];
    
      // Step 1.  Cool down every cell a little
        for( int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
          heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS_PER_STRIP) + 2));
        }
      
        // Step 2.  Heat from each cell drifts 'up' and diffuses a little
        for( int k= NUM_LEDS_PER_STRIP - 1; k >= 2; k--) {
          heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
        }
        
        // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
        if( random8() < SPARKING ) {
          int y = random8(7);
          heat[y] = qadd8( heat[y], random8(160,255) );
        }
    
        // Step 4.  Map from heat cells to LED colors
        for( int j = 0; j < NUM_LEDS_PER_STRIP; j++) {
          CRGB color = HeatColor( heat[j]);
          int pixelnumber;
          if( gReverseDirection ) {
            pixelnumber = (NUM_LEDS_PER_STRIP-1) - j;
          } else {
            pixelnumber = j;
          }
          leds[pixelnumber] = color;
        }
    }
    Last edited by siredward; 06-06-2020 at 09:35 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •