The general concept

The main purpose of the android app is to 

  • select animations
  • render animations
  • stream the "video" in the reight format using WiFi to the suit
For that we have a main feature selection view and then dedicated views for features so they can be configured. A feature usually consists of an Animation and an Activity to control it. For the Animations there is a common base class:

package com.fusionyd.supernova;
public abstract class Animation implements Runnable {
   
protected AnimationService animationService;
   
protected volatile boolean running = false;
   
public void terminate() {
       
running = false;
    }
   
protected void setAnimationService(AnimationService animationService){
       
this.animationService = animationService;
    }
   
public abstract int getMaxBrightness(); 

The animation runs then as a Thread in the background service.
there is nothing special here except of the abstract method getMax Brightness. This is used as some features cause many LEDs to light up, some features just a few. So this is kind of a protection to avoid that too much power is used.


public abstract class
FeatureActivity extends AppCompatActivity implements ServiceConnection {

   
protected AnimationService animationService = null;
    FeatureSurfaceView
featureSurfaceView;
    LinearLayout
surfaceHolder;

   
protected AnimationService getAnimationService(){         return animationService;     }
   
protected abstract LinearLayout getSurfaceHolder();
   
@Override     public void onServiceDisconnected(ComponentName name) {         animationService.setFeatureSurfaceView(null);         animationService = null;     }
   
@Override     protected void onResume() {         super.onResume();         //making sure the service is not stopped         //https://stackoverflow.com/questions/1992676/activity-app-name-has-leaked-serviceconnection-serviceconnection-name438030
       
ComponentName myService = startService(new Intent(this, AnimationService.class));
//        setImageView((ImageView) findViewById(R.id.emojiImageView));  //sma view???         Intent intent= new Intent(this, AnimationService.class);         bindService(intent, this, Context.BIND_AUTO_CREATE);         surfaceHolder = (LinearLayout) getSurfaceHolder();         surfaceHolder.addView(featureSurfaceView);     }
   
protected void onCreate(Bundle savedInstanceState){         super.onCreate(savedInstanceState);         featureSurfaceView = new FeatureSurfaceView(this);         //     }
   
@Override     public void onServiceConnected(ComponentName name, IBinder binder) {         AnimationService.MyBinder animationHandlerBinder = (AnimationService.MyBinder) binder;         animationService = animationHandlerBinder.getAnimationHandler();         animationService.setFeatureSurfaceView(featureSurfaceView);         onServiceConnected_();     }
   
/**the purpose of this method is to allow doughter classes to do seomethign after the service is connected      * this is e.g. in the SettingsActivity*/     protected void onServiceConnected_(){     }
   
@Override     protected void onPause() {         super.onPause();         surfaceHolder = (LinearLayout) getSurfaceHolder();         surfaceHolder.removeView(featureSurfaceView);         unbindService(this);     }
   
public FeatureActivity(){     } }

 


Background Service

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam porttitor augue a turpis porttitor maximus. Nulla luctus elementum felis, sit amet condimentum lectus rutrum eget.

Looping through Unicode

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam porttitor augue a turpis porttitor maximus. Nulla luctus elementum felis, sit amet condimentum lectus rutrum eget.

Mapping a bitmap to LED strips

There are plenty of ressources on the internet explaining how APA102 LED strips work. So I suggest to google on this. On our costume it is the same: The LEDS are all in one row, but for our costume it is not a straight line, but more a zig-zag. 

So somewhere we have to say, that the DOT in the Bitmap at position X=3 and Y=3 is the 23rd LED on the 4th strip. And this has to be specified for 1000 LEDs.

A first attempt looked like this:

{{10,3},{4,7}, {12,23}}

We realised, that our imagination is too small to map thousand of LEDs like this. So we decided to draw the mapping in QCAD, export it as an SVG, parse the SVG in the app and like this map it propperly. What sounds complicated was easy at the end:

  1. As we assembled the costume out of different PCB, we created these PCBs as templates in QCAD. The templates contain the order of the LEDs. On the picture on the right one can as well see, that we used small pieces around the shoulder and big pieces in the front. As we did two differnt suits to accomandate our different dress sizes, there are two different constellations
  2. The different elements where coupled with a simple line in QCAD. The start of the 7 channels is at the -1 position. This can be seen on the lower picture.
  3. QCad allows to export this as svg. The outcome is an .XML file




<!-- Linie -->
<path d="M4,9 L4,10 " style="stroke:#00ff00;stroke-width:0.25;"/>
<!-- Linie -->
<path d="M4,10 L5,10 " style="stroke:#00ff00;stroke-width:0.25;"/>
<!-- Linie -->
<path d="M5,10 L6,10 " style="stroke:#00ff00;stroke-width:0.25;"/>
<!-- Linie -->
<path d="M6,10 L7,10 " style="stroke:#00ff00;stroke-width:0.25;"/>

Send it to the costume

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam porttitor augue a turpis porttitor maximus. Nulla luctus elementum felis, sit amet condimentum lectus rutrum eget.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam porttitor augue a turpis porttitor maximus. Nulla luctus elementum felis, sit amet condimentum lectus rutrum eget.

ÜBERSCHRIFT 1

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam porttitor augue a turpis porttitor maximus. Nulla luctus elementum felis, sit amet condimentum lectus rutrum eget.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam porttitor augue a turpis porttitor maximus. Nulla luctus elementum felis, sit amet condimentum lectus rutrum eget.