Make rehabilitation encouraging and entertaining

Ligament rehabilitation for climbers requires consistent and moderate work-out training. However, it would become a tidious seesion that not everyone has the perserverance to keep it as a daily routine. Ligament Rehabilitation Incubator allows users to have fun with gachapon discoveries during their training sessions and encourage them to work out everyday.

I designed an "incubator" equipment with soft materials to improve user comfort. The device can collect data, assist in, and adjust climbers' recovery training accordingly. Those data can be used as parameters to determine the type of unknown gachapons.

Working out and having fun

Gachapons in various types give visual feedback, suggesting the progress and the quality of the training session. It's monitering the gripping presure, sweating, heart beating, temperature, and work-out progress, etc, which would further determine what will spawn from the gachapon.

Default state of various gachapons

During the training sessions

How did I made it?

The product was rapidly prototyped with the combination of Arduino Uno R3 and Processing. It contains several electronic components to detect temperature, humidity, skin conductivity, heart beats, and gripping pressure as game parameters.

#include  //import capacitive sensing library
#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

int ref0;

int led1 = 13;
int led2 = 12;



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); // *initialization - make the connection to the UNO board 
  //Serial.println(F("DHTxx test!"));

  dht.begin();
  
  ref0 = ADCTouch.read(A0, 500); //Initial reference value
  
//  pinMode(led1, OUTPUT);
//  pinMode(led2, OUTPUT);
  
}



void loop() {
  // put your main code here, to run repeatedly:
  int value0 = ADCTouch.read(A0); // Read value of pin A0

  value0 = value0 - ref0;

  //Serial.print (",");
  //delay(10);

  delay(100);


  
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  //float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  //float hic = dht.computeHeatIndex(t, h, false);
  


  if (value0 > 30) {
    digitalWrite (led1, HIGH);
    digitalWrite (led2, LOW);
  }
  else {
    digitalWrite(led1, LOW);
    digitalWrite(led2, HIGH);
  }

 Serial.print(value0);
 Serial.print(',');
 Serial.print(h);
 Serial.print(',');
 Serial.println(t);
// Serial.print(',');
// Serial.println(f);

//  Serial.print(F("Conductive Value: "));
//  Serial.print(value0);
//  Serial.print(F(" Humidity: "));
//  Serial.print(h);
//  Serial.print(F("%  Temperature: "));
//  Serial.print(t);
//  Serial.print(F("C "));
//  Serial.print(f);
//  Serial.print(F("F  Heat index: "));
//  Serial.print(hic);
//  Serial.print(F("C "));
//  Serial.print(hif);
//  Serial.println(F("F"));


  
//  digitalWrite (led1, HIGH);
//  digitalWrite (led2, LOW);
//  delay(2000);
//  digitalWrite(led1, LOW);
//  digitalWrite(led2, HIGH);
//  delay(200);

//remember to check tools => board + port
  
}

import processing.serial.*; // importing processing serial library for connecting with arduino
Serial myPort; //usb port 

String val; //incoming data from arduino as character - string
String[] stringData;
float v, h, t;
int sensorVal; //we use this variable for the data as number type

float angle = 0;
float sunMovement = 0;
float accum_v = 0;

float sun_color = 0;
float sun_radiate = 120;
float sun_radiate_alpha = 255;


//Egg egg1;
float tiltAmp = 1;
PImage grass01;
PImage grass02;
PImage grass03;
PImage grass04;

PImage egg01;
PImage egg02;
PImage egg03;
PImage egg04;

int x = 0;
int y = 0;

float spacing = 20;
float diameter = 10;

void setup(){
  size(displayWidth, displayHeight);
  //egg1 = new Egg(displayWidth/2, displayHeight/2, 0, 150);
  
  String portName = "/dev/cu.usbmodem14301"; //find port name in arduino sogtware and put it here
  myPort = new Serial(this, portName, 9600); //create serial connection
  myPort.bufferUntil('\n');
  
  //load all image
  grass01 = loadImage("Grass01.png");
  grass02 = loadImage("Grass02.png");
  grass03 = loadImage("Grass03.png");
  grass04 = loadImage("Grass04.png");
  
  egg01 = loadImage("Egg01.png");
  egg02 = loadImage("Egg02.png");
  egg03 = loadImage("Egg03.png");
  egg04 = loadImage("Egg04.png");
  
}

void draw(){
  background(255);
  float n = width / spacing;
  float a = 1;
  
  //floor
  noStroke();
  fill(245);
  rect(0, 280, displayWidth, 540);
  
  //floor dot pattern
    for (var i = 0; i < n; i++) {
      for (var j = 0; j < n; j++) {
        a *= -1;
        var x = i * spacing;
        var y = j * spacing;
        if(a > 0){
          x = x + spacing / 2;
        }    
          var d = diameter;
          fill(255);
        ellipse(x, y, d, d);
      }
    }
  
  //sun movement
  if(sunMovement <= 100){
    sunMovement += 0.15;
  }
  
  
  if(v > 7){
    noStroke();
    fill(203 - sun_color, 64 + sun_color, 66 + sun_color * 1.5, sun_radiate_alpha); 
    ellipse(1100 + sunMovement, 150 + sunMovement, sun_radiate, sun_radiate);
  }
  //noStroke();
  //fill(203 - sun_color, 64 + sun_color, 66 + sun_color * 1.5, sun_radiate_alpha); 
  //ellipse(1100 + sunMovement, 150 + sunMovement, sun_radiate, sun_radiate);
  noStroke();
  fill(203 - sun_color, 64 + sun_color, 66 + sun_color * 1.5);
  ellipse(1100 + sunMovement, 150 + sunMovement, 120, 120);
  
  if(sun_radiate < 200) {
    sun_radiate += 2;
  }
  else {
    sun_radiate = 120;
  }
  
    if(sun_radiate_alpha > 0) {
    sun_radiate_alpha -= 6.375;
  }
  else {
    sun_radiate_alpha = 255;
  }
  
  //grass backward
  image(grass04, 371, 230, 575, 246);
  image(grass03, 695, 328, 627, 217);
  
  angle += 0.05;
  //egg position and rotation
  pushMatrix();
  translate(displayWidth/2, displayHeight/2 + 100);
 
  noStroke();
  fill(220);
  ellipse(0 + cos(angle) * 10, 0, 160, 30);
  
  scale(0.3);
  rotate(cos(angle) / 8 * tiltAmp);
  image(egg01, x - egg01.width/2, y - egg01.height);
  popMatrix();
  //egg1.display();
  
  //grass frount
  image(grass02, 946, 594, 252, 172);
  image(grass01, 390, 467, 348, 221);


  //arduino data loading
  while (myPort.available() > 0){
    val = myPort.readStringUntil('\n'); // reads it and stores it in val; \n is the line break 
    //try{
    //  //val = myPort.readString();
    //  stringData = split(val, ',');
    //  //sensorVal = Integer.valueOf(val.trim()); // converts the text strin into a number
    //}
    //catch(Exception e){ 
    //}
    }
  if (val != null) {
    stringData = split(val, ',');
    float[] values = float(stringData);
    v = values[0];
    h = values[1];
    t = values[2];
  }
  
  //egg tilt value
  tiltAmp = 1 + v / 20;
  
  //sun color change
  sun_color = (h - 50) * 2;
  
  //loading bar accumulation
  if(v >= 30){
    if(accum_v < 250){
      accum_v = accum_v + v * 0.01;    
    }
    else {
      accum_v = 250;
    }
  }
  
  
  
  //temperature bar
  float pos_x = - 180;
  float pos_y = 0;
  float sphere_d = 30;
  float rect_w = 20;
  float rect_h = 120;
  float thickness = 8;
  float sphere_d_in = 30 - thickness;
  float rect_w_in = 20 - thickness;
  float rect_h_in = 120 - thickness + 4;
  float sphere_d_out = 30 + thickness - 4;
  float rect_w_out = 20 + thickness - 4;
  float rect_h_out = 120 + thickness - 6;
  float sphere_red = 30 - 1.5 * thickness;
  float rect_w_red = 20 - 1.5 * thickness;
  float rect_h_red = 120 - 1.5 * thickness + 6;
  
  float dist = 120 - (t - 26) * 50;
  
  if(dist < 0) {
    dist = 0;
  }
  else if (dist > rect_h_red){
    dist = rect_h_red;
  }
  
  pushMatrix();
  translate(displayWidth/2, displayHeight/2);
 
  noStroke();
  
  fill(255);
  ellipse(pos_x, pos_y, sphere_d_out, sphere_d_out);
  rect(pos_x - rect_w_out / 2, pos_y - rect_h_out, rect_w_out, rect_h_out, 10);
  fill(220);
  ellipse(pos_x, pos_y, sphere_d, sphere_d);
  rect(pos_x - rect_w / 2, pos_y - rect_h, rect_w, rect_h, 10);
  fill(255);
  ellipse(pos_x, pos_y, sphere_d_in, sphere_d_in);
  rect(pos_x - rect_w_in / 2, pos_y - rect_h_in, rect_w_in, rect_h_in, 10);
  fill(#cb4042);
  ellipse(pos_x, pos_y, sphere_red, sphere_red);
  rect(pos_x - rect_w_red / 2, pos_y - rect_h_red + dist, rect_w_red, rect_h_red - dist, 10);  
  popMatrix();  
  
  //loading bar
  stroke(255);
  strokeWeight(8);
  fill(255);
  rect(displayWidth/2 - 130, displayHeight/2 + 140, 260, 40, 10);
  
  noStroke();
  fill(#FFC408);
  rect(displayWidth/2 - 125, displayHeight/2 + 145, accum_v, 30, 7);
  
  stroke(220);
  strokeWeight(4);
  noFill();
  rect(displayWidth/2 - 130, displayHeight/2 + 140, 260, 40, 10);
 
  
  
 
  //tiltAmp = 1 + v / 100;
  //egg1.wobble();
  
  //print(displayWidth);
  //print(displayHeight);
  
  print(cos(angle) / 8 * tiltAmp);
  print(',');
  print(v);
  print(',');
  print(h);
  print(',');
  println(t);
  
}



class Egg {
  float x, y; // X-coordinate, y-coordinate
  float tilt; // Left and right angle offset
  float angle; // Used to define the tilt
  float scalar; // Height of the egg

  // Constructor
  Egg(float xpos, float ypos, float t, float s) {
    x = xpos;
    y = ypos;
    tilt = t;
    scalar = s / 100.0;
  }

  void wobble() {
    tilt = cos(angle) / 8 * tiltAmp;
    angle += 0.1;
  }

  void display() {
    noStroke();
    fill(200);
    pushMatrix();
    translate(x, y);
    rotate(tilt);
    scale(scalar);
    beginShape();
    vertex(0, -100);
    bezierVertex(25, -100, 40, -65, 40, -40);
    bezierVertex(40, -15, 25, 0, 0, 0);
    bezierVertex(-25, 0, -40, -15, -40, -40);
    bezierVertex(-40, -65, -25, -100, 0, -100);
    endShape();
    popMatrix();
  }
}