Introduction: Jellyfish!

This project explores a variety of materials in order to create an interactive jellyfish diorama.  The inspiration for this project came from a material called Ecoflex which is a brand of "biodegradable super soft silicone", which is somewhat translucent when formed.  It's soft rubbery look and feel also lends itself to creating sea creatures.

In order to create an interesting and interactive diorama we wanted to find a creature which had a variety of interesting behaviors we could recreate.  Bioluminescent jellyfish seemed like the obvious solution!  You can read about lots of interesting bioluminescent creatures and their behaviors here.

To create the glow found in bioluminescent jellyfish we used black light tracer known as "T-900 Series Blue Aqueous Tracer" available here.  To activate the tracer you need uv light, for this we used UV LEDs from DigiKey.  

The other major part of this project was movement of the creature.  This was accomplished with Flexinol brand muscle wire.

Main ingredients:
EcoFlex Soft Silicone
UV LEDs
T-900 Series Blue Aqueous Tracer
3-axis Accelerometer
Arduino

Step 1: Mixing EcoFlex Silicone Rubber

EcoFlex Supersoft silicone rubber is a two part silicone.  Different quantities can be ordered from here. the trial kit being sufficient for this project.

To create an item with this, the two parts are mixed in equal portions.  Before measuring out the two portions, make sure to thoroughly mix each part.  The silicone separates if not used for a while, and thoroughly mixing each part ensures best results.  Make sure to use two separate stir sticks for this, otherwise the individual parts will be contaminated.

There are a variety of ways to measure the individual parts.  For this project, a pair of large syringes were used.  Small measuring cups also work well, but are better suited for mixing larger quantities.

The two parts are poured together into a mixing cup, and then thoroughly mixed using a stir stick.  Make sure to stir such that the bottom, sides and corners of the mixing container are agitated, otherwise there will be some unmixed part of the silicone.  This may affect the cure, and could cause part of the final product to simply be a sticky liquid, rather than a smooth form.  Two minutes of mixing is usually sufficient.

Once mixed, let the silicone sit for a few minutes.  Bubbles will form after mixing, though this isn't immediately obvious.  Letting the silicone sit allows these bubbles to form and rise to the surface.  If this part is ignored, then any product placed in a close form will have bubbles embedded in it.  (The best option is to place the mixed silicone in a vacuum chamber, but this is probably outside most people's collection of tools).

Step 2: Creating Jellyfish Bell - Part I

The jellyfish bell will be created in stages.  The initial stage is to have a silicone base to build upon.  For this project, a pair of plastic bowls were used.  The bowls should be sized in such a way that one fits inside the other with a consistent gap between the surfaces of the bowls.  Ecoflex Supersoft 00-30 silicone was used to make this and the remaining parts of the jellyfish.  This product is available here.

For this step, we used the following items:

1.  Ecoflex Supersoft 00-30 silicone
2.  Two bowls of slightly different diameter
3.  Two 35 ml syringes
4.  Disposable stir sticks and mixing cups

Prior to mixing and pouring the silicone, determine the amount needed.  To do this, pour some water in the larger bowl, and press the smaller bowl inside, allowing any excess water to drain out.  Once this step is finished, suck the remaining water into one of the syringes, noting how much volume there is.  With our bowls, this needed to be done twice:  the volume ended up being ~45 ml.  Erring on the side of having too much, we mixed 50 ml of silicone.

Step 3: Working With SMA

In order to make the body move we chose to use SMA or shape memory alloy, (aka muscle wire, aka nitinol).  We used a brand called Flexinol.  Following the advice of Jie Qi in this Make Blog, here is our first curling action:



This technique involved sewing a strand of Flexinol onto one side of the paper.  When the SMA contracts it causes the paper to fold in on itself creating this movement.  

In order to translate this to the EcoFlex we needed to find a way to affix it.  We tried a similar approach, sewing the SMA onto one side of the silicone, however initial attempts were not successful.  We have various theories as to why this was the case.  For one, the silicone is sticky and the SMA may not have been strong enough to release it from the table.  Another consideration is the thickness of the silicone and thus the amount of force it requires to bend it.  

For the second attempt a much thinner piece of silicone was used with the SMA itself sewn around and through the silicone.  This showed promise as we verified the SMA could be powerful enough to actuate the silicone.

For the final version of the jellyfish we wanted to simulate a swimming motion.  To enable this we needed to be able to pull on the silicone from several sides.  This was accomplished by sending several individual strands down different parts of the bell shape.  Initially they were all connected to one conductor wire at the top and another at the bottom.  However, since the .010" gauge SMA requires 1 Amp to fully actuate, by running several in parallel we were going to need just as many amps to get them all to move.  Because amps are harder to come by in DC bricks than volts they were rewired from parallel to series.

In order to hold the SMA in place another coat of Ecoflex was poured and painted on the top of the SMA.

Driving the SMA from Arudino
Because of the high current draw required and the fact that Arduino can only source about 40mA we needed to use a switching circuit to drive the SMA.  The initial attempt was to use the same power circuit used in the "Drummer Wanted" project.  However when this was connected the Arduino did not have enough power to light up the surface mount LEDs used to illuminate the jelly.

Step 4: The First Movement

With the bell made and SMA embedded, it was time to test if it worked.



We felt this deserved its own step.

Step 5: Making It Blink and Glow

The atolla wyvillei jellyfish has some unique characteristics.  For one, it glows red as it swims through the sea.  When it comes under attack it puts on a light show known as a "burglar alarm" intended to attract other, bigger prey to scare off whatever is threatening it.


In order to achieve these states we used a red LED and a series of UV LEDs.  The hope was that by coating the jelly with black-light tracer it would give off a realistic glow under the UV lights which are reasonably close to the blue shown in the "buglar alarm" state in the above video (around 26 seconds in).

Initially we attempted to make the silicone glow by adding the black-light tracer to the silicone mix before it set, we then embedded a test UV LED in the silicone test the behavior.  Unfortunately the silicone with the tracer mixed in did not diffuse the light as much as we had hoped.  We found that we got slightly better results by simply "painting" the tracer on the outside of the silicone.

In the end the surface mount UV LEDs were soldered to a ring on the interior of the jellyfish which was connected to ground.  The 6 LEDs had individual wires fed through the middle so they could be individually addressed and blinked.  Place the ring on the interior of the bell, and secure by pouring a little silicone over the ring.

Here is the breadboard prototype of the blink routine:


Glowing
The Jellyfish also responds to light.  In order to hide from predators bioluminescent jellyfish will light up during the day and dim at night to match the ambient light.  This was accomplished with a photoresistor to detect light and a red LED controlled with a PWM output.

Step 6: Making and Attaching Tentacles

The final part of making the physical jellyfish is to make and attach tentacles to the bell of the jellyfish.  Rather than making tentacles individually, a thin sheet of silicone is made, from which tentacles can be cut.  The sheet can be made in any available container.  Plastic packaging works well, as it is readily available in many sizes, and disposable.

Pour enough silicone to make a sheet about 1/16" thick.  Once cured, peel the sheet from the form.  Using an X-Acto knife, slice individual tentacles roughly 1/8" wide.  Taper the cut so that it is a point at the tip of the tentacle. 

Tentacles will be attached to the stiffening wire in the bell using 30 gauge wire.  Thread a short piece of wire through the top of the top of each tentacle.  Once finished, thread the wire around the ring, twist to secure and clip any excess.  When finished, the jellyfish should look complete.

Step 7: User Interface

User interface is a critical component to a project such as this.  One major purpose was to demonstrate to a viewer the purpose of the "burglar alarm" action.  The atolla wyvillie jellyfish flashes the burglar alarm whenever it is attacked.  The purpose of this is to attract larger predators to itself, so that the creature attacking it is attacked.  Basically, it's considered a defense mechanism (or perhaps, a "jerk" mechanism, as the jellyfish is essentially causing one last problem for the animal eating it, rather than just being consumed gracefully like other invertebrates).

While a simple button could be employed to trigger the burglar alarm, this didn't convey the reason why this jellyfish has this behavior.  Rather, we wanted the viewer to pretend to be the attacker.  To do this, we opted to trigger the burglar alarm with a accelerometer embedded in a plush jellyfish.  The viewer picks up the plush jellyfish, and can gently shake it, as if he or she was attacking it.  In order to sense a shake, the 3 axes of the accelerometer are looked at individually for sudden changes in orientation.  Our silicone jellyfish then responds appropriately by flashing the burglar alarm.  This effectively converts interaction from passive observation (after pushing a button) to an active interaction.  We feel this approach grabs the viewer's attention, and is a particularly good way to get small children interested in the piece.

The accelerometer can be attached to the arduino using simple wires.  If available, a long ribbon cable works and looks much better.

A However, any plush jellyfish can be used as an input device.  Simply cut open the seam, and push the accelerometer in.  The L shape of the accelerometer and connector effectively wedges the device into the stuffing.  The seam could be sewed shut; we opted to leave it open.

Step 8: Putting It All Together



Here is a short video showing the jelly "swimming", going into a threat response and then going back to swimming.

Here is the Arduino code used:
/////////////////////////////////////////////////////////////
//
// Jellyfish!
//
// Jiffer Harriman and Dana Hughes
/////////////////////////////////////////////////////////////

#include <StopWatch.h>

// set pin numbers:
const int leds[] = {2, 3, 4, 5, 6, 7};
const int smaPin = 9;
const int lightPin = A5;
const int glowPin = 11;

// initial states
int ledStates[] = {LOW, LOW, LOW, LOW, LOW, LOW};
// keep track of how long its been
long previousMillis = 0;       
long interval = 100;           // interval at which to blink (milliseconds)

// are you threatening me?
boolean attack;
boolean stroke;
float sun;

// leaky integrator variables
float alpha = .5;
// a0
float a0_in = 0.0;
float a0_last = 0.0;
float a0_out = 0.0;
float a0_out_last = 0.0;
// a1
float a1_in = 0.0;
float a1_last = 0.0;
float a1_out = 0.0;
float a1_out_last = 0.0;
// a2
float a2_in = 0.0;
float a2_last = 0.0;
float a2_out = 0.0;
float a2_out_last = 0.0;
// thresholding variables
float a0_diff = 0.0;
float W0 = 0.0;

float a1_diff = 0.0;
float W1 = 0.0;

float a2_diff = 0.0;
float W2 = 0.0;

float THRESHOLD = .99;

// timer -- http://www.arduino.cc/playground/Code/StopWatchClass
StopWatch timer;
StopWatch swimTimer;

void setup() {
  Serial.begin(9600);

  // set led pins for out
  for (int i = 0; i < 6; i++){
    pinMode(leds[i], OUTPUT);
  } 

  //
  attack = false;
  stroke = false;
  // start the stopwatch
  timer.start();
  swimTimer.start();
}

void loop()
{
  sun = analogRead(lightPin) / 2.;
  Serial.println(sun);
  delay(10);
   analogWrite(glowPin, sun);
  if(checkShake()){
    attack = 1;
    int ledStates[] = {LOW, HIGH, LOW, LOW, LOW, LOW};
  }
  else if(timer.elapsed() > 9000 && attack == 1)
  {
    attack = 0;
    for (int i = 0; i < 6; i++){
      ledStates[i] = LOW;
      for (int i = 0; i < 6; i++){
        digitalWrite(leds[i], ledStates[i]);
      }
    }
    swimTimer.reset();
    swimTimer.start();
    stroke = 0;
  }

  if(attack){ 
    blinkThoseLEDs();
  }
  else
    swim();

  if (stroke)
    // turn on muscle wire pin
    digitalWrite(smaPin, HIGH);
  else  // turn off
    digitalWrite(smaPin, LOW);
}

boolean checkShake(){
  // leaky integrator x3
  a0_in = analogRead(A0);
  a0_out = a0_in * alpha + (1 - alpha) * a0_out_last;
  a0_out_last = a0_out;

  a1_in = analogRead(A1);
  a1_out = a1_in * alpha + (1 - alpha) * a1_out_last;
  a1_out_last = a1_out;

  a2_in = analogRead(A2);
  a2_out = a2_in * alpha + (1 - alpha) * a2_out_last;
  a2_out_last = a2_out;

  // Detect onsets
  a0_diff = abs(a0_in - a0_out_last);
  W0 = a0_diff / a0_out;

  a1_diff = abs(a1_in - a1_out_last);
  W1 = a1_diff / a1_out;

  a2_diff = abs(a2_in - a2_out_last);
  W2 = a2_diff / a2_out;

  // registered a beat
  boolean ouch = false;
  if(W0 > THRESHOLD || W1 > THRESHOLD || W2 > THRESHOLD)
  {

    ouch = true;
    // reset the timer
    timer.reset();
    timer.start();

    // stop swimming! you're being attacked
    swimTimer.reset();
    swimTimer.start();
    stroke = 0;

  }

  return ouch;
}

void blinkThoseLEDs(){
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;  

  // which one went last?
    int lastOn;

    for (int i = 0; i < 6; i++){
      if (ledStates[i] == HIGH)
      {
        ledStates[i] = LOW;
        lastOn = i;
      }
    }

    if (lastOn > 4){
      lastOn = -1;
    }
    ledStates[lastOn+1] = HIGH;
    for (int i = 0; i < 6; i++){
      digitalWrite(leds[i], ledStates[i]);
    }
  }
}

void swim(){
  if (swimTimer.elapsed() > 6000 && stroke == 0)
  {
    stroke = 1;
  }
  else if(swimTimer.elapsed() > 10000)
  {
    stroke = 0;
    swimTimer.reset();
    swimTimer.start();
  }
}