Otamatone button for slow shutdown

Hi all,

A time ago I did nessun dorma on an otamatone. Halfway during the song I noticed my batteries were running low and had to sing it instead… This was however… Pretty good comedy. So now I want to recreate it. So I want to create a gradually failing otamatone. Slowly reducing the input voltage.

Here I’m running into some issues. First I just tried to put a big condenser from vcc to gnd, like a power supply hoping it would give enough juice to slowly turn it off… It however does not.

So I just tried a switch with a resistor from vcc. It’s not really the effect I was looking for. I want it to gradually fail… (note: Even a low resistor on the power gives enough resistance to make it go super quiet. 330 ohm makes it not turn on. 220 is borderline not hearable. 47 ohm is noticably quieter.)

So I tried an arduino. I got the code to work that when pressing a momentary button. Voltage drops from 5v to 0v in 30 seconds. When connecting the otamatone… It doesn’t work… Not enough amperage.

Ok… So… A vactrol was my next thought. connecting it in series with the power supply. However even with full brightness… I get too much resistance. So this means I can hardly hear it with the vactrol on its lowest resistance…

So how would I go about solving this pickle? Another opamp that can handle more amperage? I’m also reading up on using a transistor as a buffer to handle more amperage?
So I would need a bjt transistor that can handle 500ma at 5v max. Ok I’m finding my answer as I’m typing here I guess… I’ll go over the transistors I have lieing around and see if any meet the criteria. No idea if I need to buffer it beforehand…

I’ll post anyway… I deleted my previous post as I figured it out along the way. I’ll keep this one as a diary entry. And updating myself if this indeed helps fix it and finetune it.

How big is big? If you could measure the current it draws, the typical time for it to shut down is t = C*V/I, where V is the battery voltage. I would expect, for t to be in the order of seconds, C would need to be in the order of 0.1-1 F. That would put you in supercapacitor territory.

1 Like

Just measured the amperage the otamatone draws and I measured a max of 175mA. (probably a bit higher peaks). 20mA when Idle.

I used a 3300uF capacitor. (Noticed I dutchified my english… Of course I meant a capacitor. not a condenser… Which is also an english word, although I never heard it used instead of a capacitor)

Going to test some transistors now. Knowing I need around 200mA of current.

2 Likes

Don’t worry, fellow Dutchie here :smile:

I think if you were to grab a 0.5F 5V supercap, you’ll get some better results.

1 Like

Update:

So what I’ve tried:

  • Going from my dac to an lm358 op-amp
    result: Got 1v under my preferred voltage, because op-amp doesn’t reach supply voltage.

  • Increase supply voltage to 18v with 2 9v batteries in series.

  • Half succes. Almost there… Except it draws a max of 60mA? So it works… but it just a bit too soft.

  • Tried a transistor buffer with a bc337. Same result as the op-amp…

  • I removed the 1k resistor from the output of the dac to the base of the transistor to increase the base current.

  • succes! I’ll post a more detailed schematic and code. Also for my own future reference.

1 Like

Currently I’m using this code (might still adjust to taste… Because it’s not quite the effect yet. But everything is working)

When holding the button for 2 or more seconds. Otamatone gets 5v.
When pressing the button 1 time. The otamatone gets 5v or 0v alternating semi randomly, but increasing in frequency.
Pressing the button again, makes it go from 5v to 2.5v (which is the voltage at around which the otamatone shuts off.)

Now I’m thinking about being able to modify the ribbon controller, so I can make it sing on it’s own. But the housing is quiete small, so I’m not sure yet how I would wire it.

#include <Adafruit_MCP4725.h>

#define BUTTON_PIN 2
#define MCP4725_ADDRESS 0x60

Adafruit_MCP4725 dac;

enum State { IDLE, ALTERNATING_VOLTAGE, TRANSITION_DOWN, TRANSITION_DOWN_ALTERNATE };
State state = IDLE;

bool buttonState = false; // Current state of the button
bool lastButtonState = false; // Previous state of the button
unsigned long buttonPressStartTime = 0; // Time when button was pressed
const unsigned long LONG_PRESS_DURATION = 2000; // 2 seconds
const unsigned long TRANSITION_DURATION = 15000; // 15 seconds
unsigned long alternatingVoltageStartTime = 0; // Time when alternating voltage started
unsigned long alternatingVoltageDurationOn = 1000; // Initial duration for on state (0.1 to 1 second)
unsigned long alternatingVoltageDurationOff = 150; // Initial duration for off state (0.05 to 0.2 seconds)
float currentVoltage = 0.0; // Current voltage state
bool voltageOn = false; // Flag to track voltage state
unsigned long startTime = 0; // Start time for gradual speed increase
const unsigned long SPEED_UP_DURATION = 10000; // Duration over which to increase speed
unsigned long transitionDownStartTime = 0; // Start time for gradual voltage decrease
const unsigned long TRANSITION_DOWN_DURATION = 10000; // 10 seconds

void setup() {
  pinMode(BUTTON_PIN, INPUT); // No internal pull-up
  Serial.begin(9600);

  if (!dac.begin(MCP4725_ADDRESS)) {
    Serial.println("Failed to find MCP4725 chip");
    while (1) { delay(10); }
  }
  setVoltage(0); // Set initial voltage to 0V
  Serial.println("Setup complete. Initial voltage set to 0V.");
}

void loop() {
  buttonState = digitalRead(BUTTON_PIN);
  
  // Check for button press (state change from LOW to HIGH)
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPressStartTime = millis();
    } else {
      handleButtonPress();
    }
    delay(50); // Debounce delay
  }
  
  lastButtonState = buttonState;

  // Handle the gradual transition
  if (state == TRANSITION_DOWN) {
    unsigned long elapsedTime = millis() - transitionDownStartTime;
    if (elapsedTime <= TRANSITION_DOWN_DURATION) {
      float voltage = 5.0 - (2.5 * (elapsedTime / (float)TRANSITION_DOWN_DURATION));
      setVoltage(voltage);
    } else {
      setVoltage(2.5); // Ensure voltage is set to 2.5V after transition
      state = IDLE;
      Serial.println("Transition down complete. Voltage set to 2.5V.");
    }
  } else if (state == ALTERNATING_VOLTAGE) {
    unsigned long currentTime = millis();
    unsigned long elapsedTime = currentTime - alternatingVoltageStartTime;

    if (voltageOn) {
      if (elapsedTime >= alternatingVoltageDurationOn) {
        // Turn voltage off
        setVoltage(0);
        voltageOn = false;
        // Generate a random duration for off state within updated range
        alternatingVoltageDurationOff = random(10, 30); // Between 0.01 and 0.03 seconds
        alternatingVoltageStartTime = currentTime;
      }
    } else {
      if (elapsedTime >= alternatingVoltageDurationOff) {
        // Turn voltage on
        setVoltage(5);
        voltageOn = true;
        // Generate a random duration for on state within updated range
        alternatingVoltageDurationOn = random(50, 150); // Between 0.05 and 0.15 seconds
        alternatingVoltageStartTime = currentTime;
      }
    }
  } else if (state == TRANSITION_DOWN_ALTERNATE) {
    setVoltage(5); // Set voltage to 5V
    state = TRANSITION_DOWN; // Start transitioning down to 2.5V
    transitionDownStartTime = millis();
    Serial.println("Starting transition down to 2.5V.");
  }

  // Gradually increase speed over time
  unsigned long currentTime = millis();
  if (currentTime - startTime <= SPEED_UP_DURATION) {
    float progress = (currentTime - startTime) / (float)SPEED_UP_DURATION;
    // Update duration ranges for on and off states based on progress
    alternatingVoltageDurationOn = lerp(1000, 150, progress); // From 1000 to 150 milliseconds
    alternatingVoltageDurationOff = lerp(150, 30, progress); // From 150 to 30 milliseconds
  }
}

void handleButtonPress() {
  unsigned long pressDuration = millis() - buttonPressStartTime;

  if (pressDuration >= LONG_PRESS_DURATION) {
    // Long press: Reset to 5V and reset state
    setVoltage(5);
    state = IDLE;
    Serial.println("Long press detected. Resetting to 5V.");
  } else {
    // Short press: Change state based on current state
    switch (state) {
      case IDLE:
        state = ALTERNATING_VOLTAGE;
        Serial.println("Alternating voltage mode activated.");
        startTime = millis(); // Start time for gradual speed increase
        break;
      case ALTERNATING_VOLTAGE:
        state = TRANSITION_DOWN_ALTERNATE;
        Serial.println("Transitioning down after alternating voltages.");
        break;
    }
  }
}

void setVoltage(float voltage) {
  // Ensure voltage is within 0V and 5V range
  voltage = constrain(voltage, 0, 5.0);
  uint16_t dacValue = (uint16_t)(voltage / 5.0 * 4095);
  dac.setVoltage(dacValue, false);
  currentVoltage = voltage; // Update current voltage state
  Serial.print("Voltage set to ");
  Serial.print(voltage);
  Serial.println("V");
}

float lerp(float start, float end, float t) {
  return start + t * (end - start);
}

Setup:

9v battery
Arduino nano
bc337
Mcp4725 (dac)
1x 1M resistor
1x 10k resistor
1x momentary push button

I’m connecting the mcp as per usual to the arduino (A4 and A5 on the arduino and providing vcc and gnd connections)

The button is connected with 5v from the arduino and pin d2

The output of the mcp is going to the base of the bc337.
The collector of the bc337 is connected to the 9v battery
The emitter is connected to the power input of the otamatone and with a 1M resistor to gnd.
→ This transistor buffer is used to provide enough amperage to the otamatone, which the arduino can’t provide.

A picture of my pro setup: