Project in progress
Flip

Flip

Fins that enhance a child's magical experience from swimming.

  • 1,461 views
  • 7 comments
  • 3 respects

Components and supplies

A000053 iso both1
Arduino Micro & Genuino Micro
×1
Adafruit nRF8001 Bluetooth LE
×1
Adafruit MMA8451 Accelerometer Breakout
×1
Adafruit PowerBoost 500 Basic
×1
Adafruit 1.8 TFT LCD with MicroSd Card Breakout ST7735R
×1
Lithium Ion Polymer Battery- 3.7V 1200MAh
×1
Pair of Pre-made Silicone Glove Fins
×1
Spandex Fabric (ft)
×2
Velcro Pads (pkg)
×2
Velcro Strips
×1
Zip Ties
×2
Jumper Cables
×22

About this project

Flip Intro


There is something kind of magical about swimming when you are a child. Do you remember growing up and watching your shadow as you swam in the pool, trying to mimic a perfect dolphin kick and imagining you were a mermaid rather than human?  We all shared these sorts of memories and a few of us decided to create something that enhanced the sense of wonder kids’ get when they play and swim under water.


Video


Value Proposition


1. Swimming is a great form of exercise. One of the core objectives of Flip is to help kids to become healthy and competent swimmers. 

2. However, another goal of this design is to make kids learn and care about water animals. Traditionally, aquariums have been a way of bringing people, and especially children, closer to sea life. By triggering a sense of wonder and appreciation in visitors, aquariums are an effective way of teaching people about sea-life preservation, and it’s also just really fun to learn about these animals and their habitats.  


Ideation


We saw an opportunity to create a device that not only encouraged children to swim more, but also generated their interest in preserving sea creatures and their habitats through a fun interaction.  We eventually imagined designing a pair of webbed aquatic gloves that would track acceleration.  It would then sync with an educational mobile app in order to generate animal profiles real-time.  Our desire is to promote learning through animal-metrics.

In our works-alike glove (see images below), we used simple material like fabric, Velcro and a pre-made fin to mock-up a simple casing that would be easy to work with.


Aqua Glove Demonstration Prototype

Glove mock-up.

But for our actual prototype, we imagined using materials like silicone, which composes the glove and fin, and an elastomer material for the wristband.

The wristband houses all the hardware that stimulates the child's magical experience.  It hides everything that doesn't want to be seen.  The screen is the only component that is exposed, which would be waterproofed so children can, of course, swim with the glove.


Hardware/Sensors

Aqua Glove Prototype

Glove

Target Users


Our target users are children ages 4-9. On average in the United States, children learn to swim at age 4. We felt that this product would be best suited for kids who feel comfortable in the water but will be engaged with this simple interface. 

Aquariums and books are great educational tools, but our product exposes kids to sea-life in a new way. By making them “feel” like they themselves ARE different animals while understanding the different marine life found in different geographies, Flip creates an experience that is highly engaging. Best of all, this product is fun and encourages kids to swim and care about sea creatures in a way that will hopefully encourage them to connect and care about their endangered habitats as they grow older.


Android & Mock ups

UI

Arduino

Arduino code
Untitled file

Warning: Embedding code files within the project story has been deprecated. To edit this file or add more files, go to the "Software" tab. To remove this file from the story, click on it to trigger the context menu, then click the trash can button (this won't delete it from the "Software" tab).

#include <SPI.h>
// For Bluetooth
#include <Adafruit_BLE_UART.h>
// For Accelerometer
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>
// For OLED Screen
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>

// Accelerometer
Adafruit_MMA8451 accelerometer = Adafruit_MMA8451();

// Bluetooth LE
#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 1
#define ADAFRUITBLE_RST 9

Adafruit_BLE_UART BLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);

// OLED Screen
#define OLED_SCLK A0
#define OLED_MOSI A1
#define OLED_CS   8
#define OLED_RST  7
#define OLED_DC   6

// Color definitions
#define BLACK           0x0000
#define RED             0xF800
#define CYAN            0x07FF
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

Adafruit_SSD1331 display = Adafruit_SSD1331(OLED_CS, OLED_DC, OLED_MOSI, OLED_SCLK, OLED_RST);

void setup(void)
{
  Serial.begin(9600);
  
  // Setup OLED
  display.begin();

  drawFlip();
  
  // Setup BLE
  BLEserial.setDeviceName("Flip"); // 7 Characters Max
  BLEserial.begin();

  // Setup Accelerometer
  if (!accelerometer.begin()) {
    Serial.println("Couldn't Start");
    while (1);
  }
  Serial.println("Accelerometer Found");

  accelerometer.setRange(MMA8451_RANGE_2_G);
  Serial.print("Range = "); Serial.print(2 << accelerometer.getRange());
}

aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;
int counter = 0;
String lastMovement = "";
uint16_t time = millis();
String accel_buffer[10];
boolean sent = false;

void loop()
{
  // Tell the nRF8001 to do whatever it should be working on.
  BLEserial.pollACI();

  // Ask what is our current status
  aci_evt_opcode_t status = BLEserial.getState();

  // If the status changed.
  if (status != laststatus) {
    if (status == ACI_EVT_DEVICE_STARTED) {
      Serial.println(F("* Advertising started"));
    }

    if (status == ACI_EVT_CONNECTED) {
      Serial.println(F("* Connected!"));
    }

    if (status == ACI_EVT_DISCONNECTED) {
      Serial.println(F("* Disconnected or advertising timed out"));
    }

    laststatus = status;
  }

  if (status == ACI_EVT_CONNECTED) {
    // Check for data
    if (BLEserial.available()) {
      Serial.print("* ");
      Serial.print(BLEserial.available());
      Serial.println(F(" bytes available from BTLE"));
    }

    // While there is something to read, read the next char
    while (BLEserial.available()) {
      char c = BLEserial.read();
      Serial.print(c);
    }

    Serial.setTimeout(100);
    
    if (!sent) {
      bleSend();
    }

    // Print for Debugging
    // Serial.print(F("\n* Sending -> \""));
    // Serial.print((char *)sendbuffer);
    // Serial.println("\"");
  } else {
    int index = counter % 10;
    accel_buffer[index] = getAcceleration();
    counter += 1;
    
    if (counter == 10) {
      counter = 0;
    }
    
    if (isMoving()) {
      if (lastMovement != "m") {
        drawFish();
        lastMovement = "m";
        time = millis();
      }
    } else {
      if (lastMovement != "s" && (millis() - time > 2500)) {
        drawStarfish();
        lastMovement = "s";
      }
    }
  }

  delay(1000);
}

void bleSend()
{
  int k;
  for (k = 0; k < 10; k += 1) {
    // Get buffer length
    uint8_t sendbuffer[20];
    accel_buffer[k].getBytes(sendbuffer, 20);
    char sendbuffersize = min(20, accel_buffer[k].length());
    
    // Write to BLE buffer
    BLEserial.write(sendbuffer, sendbuffersize);
    delay(200);
  }
  
  sent = true;
}

// Get Accelerometer Acceleration
String getAcceleration()
{
  // Read the 'raw' data in 14-bit counts
  accelerometer.read();
  // Get a new sensor event
  sensors_event_t event;
  accelerometer.getEvent(&event);
  // Get acceleration in m/(s^2)
  float accel_x = event.acceleration.x;
  float accel_y = event.acceleration.y;
  float accel_z = event.acceleration.z;

  String x = String(accel_x, 2);
  String y = String(accel_y, 2);

  String data = x + "," + y + "," + z + "\n";
  return data;
}

boolean isMoving()
{
  accelerometer.read();
  // Get a new sensor event
  sensors_event_t event;
  accelerometer.getEvent(&event);
  
  float accel_x = event.acceleration.x;
  float accel_y = event.acceleration.y;
  
  if (abs(accel_x) > 0.15 || abs(accel_y) > 0.15) {
    return true;
  } else {
    return false;
  }
}

void drawFlip(void) {
  display.fillScreen(BLACK);
  
  display.drawFastVLine(21, 17, 4, CYAN);
  display.drawFastVLine(21, 40, 3, CYAN);
  display.drawFastVLine(22, 17, 4, CYAN);
  display.drawFastVLine(22, 40, 3, CYAN);
  display.drawFastVLine(23, 18, 5, CYAN);
  display.drawFastVLine(23, 36, 6, CYAN);
  display.drawFastVLine(24, 20, 8, CYAN);
  display.drawFastVLine(24, 31, 9, CYAN);
  display.drawFastVLine(25, 20, 20, CYAN);
  display.drawFastVLine(26, 21, 17, CYAN);
  display.drawFastVLine(27, 25, 8, CYAN);
  display.fillRect(28, 28, 14, 4, CYAN);
  display.fillRect(32, 20, 5, 22, CYAN);
  display.fillRect(34, 18, 9, 2, CYAN); 
  display.drawFastHLine(35, 17, 8, CYAN);
  display.drawFastHLine(37, 16, 5, CYAN);
  display.fillRect(46, 17, 4, 25, CYAN);
  display.fillRect(53, 17, 4, 5, CYAN);
  display.fillRect(53, 25, 4, 17, CYAN);
  display.fillRect(61, 27, 4, 26, CYAN);
  display.fillRect(65, 28, 2, 14, CYAN);
  display.fillRect(67, 27, 2, 14, CYAN);
  display.fillRect(67, 27, 7, 4, CYAN);
  display.fillRect(67, 39, 7, 4, CYAN);
  display.fillRect(73, 30, 3, 10, CYAN);
  display.fillRect(72, 28, 3, 4, CYAN);
  display.drawFastVLine(76, 32, 6, CYAN);
  
  delay(2000);
}

void drawFish(void) {
  display.fillScreen(BLACK);
  
  display.fillRect(22, 31, 67, 5, YELLOW);
  
  display.fillRect(23, 28, 65, 3, YELLOW);
  display.fillRect(23, 36, 65, 3, YELLOW);
  
  display.fillRect(24, 26, 63, 2, YELLOW);
  display.fillRect(24, 39, 63, 2, YELLOW);

  display.fillRect(25, 24, 60, 2, YELLOW);
  display.fillRect(25, 41, 60, 2, YELLOW);

  display.fillRect(27, 22, 56, 2, YELLOW);
  display.fillRect(27, 43, 56, 2, YELLOW);

  display.fillRect(30, 20, 51, 2, YELLOW);
  display.fillRect(30, 45, 51, 2, YELLOW);
  
  display.drawFastHLine(33, 19, 45, YELLOW);
  display.drawFastHLine(33, 47, 45, YELLOW);
  
  display.drawFastHLine(35, 18, 41, YELLOW);
  display.drawFastHLine(35, 48, 41, YELLOW);

  display.drawFastHLine(38, 17, 35, YELLOW);
  display.drawFastHLine(38, 49, 35, YELLOW);

  display.drawFastHLine(43, 16, 25, YELLOW);
  display.drawFastHLine(43, 50, 25, YELLOW);

  display.drawFastHLine(50, 15, 11, YELLOW);
  display.drawFastHLine(50, 51, 11, YELLOW);
  
  display.fillTriangle(10, 16, 28, 33, 10, 50, YELLOW);
  delay(500);
}

void drawStarfish(void) {
  display.fillScreen(BLACK);
  
  display.fillRect(40, 24, 21, 20, RED);
  
  display.fillRect(45, 9, 4, 15, RED);
  display.drawPixel(41, 23, RED);
  display.drawFastVLine(42, 19, 5, RED);
  display.drawFastVLine(43, 15, 9, RED);
  display.drawFastVLine(44, 13, 11, RED);
  display.fillRect(46, 7, 2, 2, RED);
  display.drawFastVLine(49, 11, 13, RED);
  display.drawFastVLine(50, 15, 9, RED);
  display.drawFastVLine(51, 18, 6, RED);
  display.drawFastVLine(52, 22, 2, RED);
  
  display.drawPixel(60, 23, RED);
  display.fillRect(61, 23, 3, 10, RED);
  display.fillRect(64, 22, 3, 9, RED);
  display.drawFastVLine(67, 21, 9, RED);
  display.fillRect(68, 20, 2, 9, RED);
  display.drawFastVLine(70, 19, 9, RED);
  display.drawFastVLine(71, 19, 7, RED);
  display.drawPixel(66, 21, RED);
  display.drawFastVLine(61, 33, 2, RED);
  display.fillRect(72, 18, 2, 5, RED);
  display.drawFastVLine(74, 18, 3, RED);
  
  display.fillRect(56, 44, 14, 4, RED);
  display.drawFastVLine(61, 38, 6, RED);
  display.fillRect(62, 41, 3, 3, RED);
  display.drawFastHLine(65, 43, 3, RED);
  display.fillRect(70, 45, 2, 3, RED);
  display.drawFastVLine(72, 46, 3, RED);
  display.fillRect(60, 48, 12, 2, RED);
  display.drawFastHLine(53, 44, 3, RED);
  display.drawFastHLine(54, 45, 2, RED);
  display.drawFastHLine(57, 48, 3, RED);
  display.drawFastHLine(64, 50, 4, RED);
  
  display.fillRect(39, 44, 9, 7, RED);
  display.fillRect(37, 51, 8, 4, RED);
  display.drawFastVLine(39, 41, 3, RED);
  display.drawFastVLine(38, 45, 6, RED);
  display.drawFastVLine(48, 44, 4, RED);
  display.drawFastHLine(45, 51, 2, RED);
  display.drawFastHLine(36, 55, 8, RED);
  display.drawFastHLine(36, 56, 5, RED);
  display.drawFastHLine(37, 57, 2, RED);
  
  display.fillRect(34, 27, 6, 8, RED);
  display.fillRect(29, 26, 5, 6, RED);
  display.fillRect(25, 25, 4, 4, RED);
  display.drawFastHLine(37, 35, 3, RED);
  display.drawFastHLine(31, 32, 3, RED);
  display.drawFastHLine(26, 29, 3, RED);
  display.drawFastVLine(24, 26, 3, RED);
  display.drawPixel(39, 36, RED);
  display.drawPixel(33, 33, RED);
  display.drawPixel(28, 30, RED);
  display.drawPixel(29, 25, RED);
  display.drawPixel(39, 26, RED);
  delay(500);
}

Next Steps


We believe this product can be developed even further to include more opportunities for education, play, and fitness. Including additional sensors to detect water ion concentration and temperature would allow for even more advanced animals profiles. We’ve also brainstormed ways we could create interaction between multiple Flip users, allowing for a new spin on age-old favorite like sharks and minows.

Flip style guide

Code

fins.inoPlain text
Arduino code
#include <SPI.h>
// For Bluetooth
#include <Adafruit_BLE_UART.h>
// For Accelerometer
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>
// For OLED Screen
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>

// Accelerometer
Adafruit_MMA8451 accelerometer = Adafruit_MMA8451();

// Bluetooth LE
#define ADAFRUITBLE_REQ 10
#define ADAFRUITBLE_RDY 1
#define ADAFRUITBLE_RST 9

Adafruit_BLE_UART BLEserial = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);

// OLED Screen
#define OLED_SCLK A0
#define OLED_MOSI A1
#define OLED_CS   8
#define OLED_RST  7
#define OLED_DC   6

// Color definitions
#define BLACK           0x0000
#define RED             0xF800
#define CYAN            0x07FF
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

Adafruit_SSD1331 display = Adafruit_SSD1331(OLED_CS, OLED_DC, OLED_MOSI, OLED_SCLK, OLED_RST);

void setup(void)
{
  Serial.begin(9600);
  
  // Setup OLED
  display.begin();

  drawFlip();
  
  // Setup BLE
  BLEserial.setDeviceName("Flip"); // 7 Characters Max
  BLEserial.begin();

  // Setup Accelerometer
  if (!accelerometer.begin()) {
    Serial.println("Couldn't Start");
    while (1);
  }
  Serial.println("Accelerometer Found");

  accelerometer.setRange(MMA8451_RANGE_2_G);
  Serial.print("Range = "); Serial.print(2 << accelerometer.getRange());
}

aci_evt_opcode_t laststatus = ACI_EVT_DISCONNECTED;
int counter = 0;
String lastMovement = "";
uint16_t time = millis();
String accel_buffer[10];
boolean sent = false;

void loop()
{
  // Tell the nRF8001 to do whatever it should be working on.
  BLEserial.pollACI();

  // Ask what is our current status
  aci_evt_opcode_t status = BLEserial.getState();

  // If the status changed.
  if (status != laststatus) {
    if (status == ACI_EVT_DEVICE_STARTED) {
      Serial.println(F("* Advertising started"));
    }

    if (status == ACI_EVT_CONNECTED) {
      Serial.println(F("* Connected!"));
    }

    if (status == ACI_EVT_DISCONNECTED) {
      Serial.println(F("* Disconnected or advertising timed out"));
    }

    laststatus = status;
  }

  if (status == ACI_EVT_CONNECTED) {
    // Check for data
    if (BLEserial.available()) {
      Serial.print("* ");
      Serial.print(BLEserial.available());
      Serial.println(F(" bytes available from BTLE"));
    }

    // While there is something to read, read the next char
    while (BLEserial.available()) {
      char c = BLEserial.read();
      Serial.print(c);
    }

    Serial.setTimeout(100);
    
    if (!sent) {
      bleSend();
    }

    // Print for Debugging
    // Serial.print(F("\n* Sending -> \""));
    // Serial.print((char *)sendbuffer);
    // Serial.println("\"");
  } else {
    int index = counter % 10;
    accel_buffer[index] = getAcceleration();
    counter += 1;
    
    if (counter == 10) {
      counter = 0;
    }
    
    if (isMoving()) {
      if (lastMovement != "m") {
        drawFish();
        lastMovement = "m";
        time = millis();
      }
    } else {
      if (lastMovement != "s" && (millis() - time > 2500)) {
        drawStarfish();
        lastMovement = "s";
      }
    }
  }

  delay(1000);
}

void bleSend()
{
  int k;
  for (k = 0; k < 10; k += 1) {
    // Get buffer length
    uint8_t sendbuffer[20];
    accel_buffer[k].getBytes(sendbuffer, 20);
    char sendbuffersize = min(20, accel_buffer[k].length());
    
    // Write to BLE buffer
    BLEserial.write(sendbuffer, sendbuffersize);
    delay(200);
  }
  
  sent = true;
}

// Get Accelerometer Acceleration
String getAcceleration()
{
  // Read the 'raw' data in 14-bit counts
  accelerometer.read();
  // Get a new sensor event
  sensors_event_t event;
  accelerometer.getEvent(&event);
  // Get acceleration in m/(s^2)
  float accel_x = event.acceleration.x;
  float accel_y = event.acceleration.y;
  float accel_z = event.acceleration.z;

  String x = String(accel_x, 2);
  String y = String(accel_y, 2);

  String data = x + "," + y + "," + z + "\n";
  return data;
}

boolean isMoving()
{
  accelerometer.read();
  // Get a new sensor event
  sensors_event_t event;
  accelerometer.getEvent(&event);
  
  float accel_x = event.acceleration.x;
  float accel_y = event.acceleration.y;
  
  if (abs(accel_x) > 0.15 || abs(accel_y) > 0.15) {
    return true;
  } else {
    return false;
  }
}

void drawFlip(void) {
  display.fillScreen(BLACK);
  
  display.drawFastVLine(21, 17, 4, CYAN);
  display.drawFastVLine(21, 40, 3, CYAN);
  display.drawFastVLine(22, 17, 4, CYAN);
  display.drawFastVLine(22, 40, 3, CYAN);
  display.drawFastVLine(23, 18, 5, CYAN);
  display.drawFastVLine(23, 36, 6, CYAN);
  display.drawFastVLine(24, 20, 8, CYAN);
  display.drawFastVLine(24, 31, 9, CYAN);
  display.drawFastVLine(25, 20, 20, CYAN);
  display.drawFastVLine(26, 21, 17, CYAN);
  display.drawFastVLine(27, 25, 8, CYAN);
  display.fillRect(28, 28, 14, 4, CYAN);
  display.fillRect(32, 20, 5, 22, CYAN);
  display.fillRect(34, 18, 9, 2, CYAN); 
  display.drawFastHLine(35, 17, 8, CYAN);
  display.drawFastHLine(37, 16, 5, CYAN);
  display.fillRect(46, 17, 4, 25, CYAN);
  display.fillRect(53, 17, 4, 5, CYAN);
  display.fillRect(53, 25, 4, 17, CYAN);
  display.fillRect(61, 27, 4, 26, CYAN);
  display.fillRect(65, 28, 2, 14, CYAN);
  display.fillRect(67, 27, 2, 14, CYAN);
  display.fillRect(67, 27, 7, 4, CYAN);
  display.fillRect(67, 39, 7, 4, CYAN);
  display.fillRect(73, 30, 3, 10, CYAN);
  display.fillRect(72, 28, 3, 4, CYAN);
  display.drawFastVLine(76, 32, 6, CYAN);
  
  delay(2000);
}

void drawFish(void) {
  display.fillScreen(BLACK);
  
  display.fillRect(22, 31, 67, 5, YELLOW);
  
  display.fillRect(23, 28, 65, 3, YELLOW);
  display.fillRect(23, 36, 65, 3, YELLOW);
  
  display.fillRect(24, 26, 63, 2, YELLOW);
  display.fillRect(24, 39, 63, 2, YELLOW);

  display.fillRect(25, 24, 60, 2, YELLOW);
  display.fillRect(25, 41, 60, 2, YELLOW);

  display.fillRect(27, 22, 56, 2, YELLOW);
  display.fillRect(27, 43, 56, 2, YELLOW);

  display.fillRect(30, 20, 51, 2, YELLOW);
  display.fillRect(30, 45, 51, 2, YELLOW);
  
  display.drawFastHLine(33, 19, 45, YELLOW);
  display.drawFastHLine(33, 47, 45, YELLOW);
  
  display.drawFastHLine(35, 18, 41, YELLOW);
  display.drawFastHLine(35, 48, 41, YELLOW);

  display.drawFastHLine(38, 17, 35, YELLOW);
  display.drawFastHLine(38, 49, 35, YELLOW);

  display.drawFastHLine(43, 16, 25, YELLOW);
  display.drawFastHLine(43, 50, 25, YELLOW);

  display.drawFastHLine(50, 15, 11, YELLOW);
  display.drawFastHLine(50, 51, 11, YELLOW);
  
  display.fillTriangle(10, 16, 28, 33, 10, 50, YELLOW);
  delay(500);
}

void drawStarfish(void) {
  display.fillScreen(BLACK);
  
  display.fillRect(40, 24, 21, 20, RED);
  
  display.fillRect(45, 9, 4, 15, RED);
  display.drawPixel(41, 23, RED);
  display.drawFastVLine(42, 19, 5, RED);
  display.drawFastVLine(43, 15, 9, RED);
  display.drawFastVLine(44, 13, 11, RED);
  display.fillRect(46, 7, 2, 2, RED);
  display.drawFastVLine(49, 11, 13, RED);
  display.drawFastVLine(50, 15, 9, RED);
  display.drawFastVLine(51, 18, 6, RED);
  display.drawFastVLine(52, 22, 2, RED);
  
  display.drawPixel(60, 23, RED);
  display.fillRect(61, 23, 3, 10, RED);
  display.fillRect(64, 22, 3, 9, RED);
  display.drawFastVLine(67, 21, 9, RED);
  display.fillRect(68, 20, 2, 9, RED);
  display.drawFastVLine(70, 19, 9, RED);
  display.drawFastVLine(71, 19, 7, RED);
  display.drawPixel(66, 21, RED);
  display.drawFastVLine(61, 33, 2, RED);
  display.fillRect(72, 18, 2, 5, RED);
  display.drawFastVLine(74, 18, 3, RED);
  
  display.fillRect(56, 44, 14, 4, RED);
  display.drawFastVLine(61, 38, 6, RED);
  display.fillRect(62, 41, 3, 3, RED);
  display.drawFastHLine(65, 43, 3, RED);
  display.fillRect(70, 45, 2, 3, RED);
  display.drawFastVLine(72, 46, 3, RED);
  display.fillRect(60, 48, 12, 2, RED);
  display.drawFastHLine(53, 44, 3, RED);
  display.drawFastHLine(54, 45, 2, RED);
  display.drawFastHLine(57, 48, 3, RED);
  display.drawFastHLine(64, 50, 4, RED);
  
  display.fillRect(39, 44, 9, 7, RED);
  display.fillRect(37, 51, 8, 4, RED);
  display.drawFastVLine(39, 41, 3, RED);
  display.drawFastVLine(38, 45, 6, RED);
  display.drawFastVLine(48, 44, 4, RED);
  display.drawFastHLine(45, 51, 2, RED);
  display.drawFastHLine(36, 55, 8, RED);
  display.drawFastHLine(36, 56, 5, RED);
  display.drawFastHLine(37, 57, 2, RED);
  
  display.fillRect(34, 27, 6, 8, RED);
  display.fillRect(29, 26, 5, 6, RED);
  display.fillRect(25, 25, 4, 4, RED);
  display.drawFastHLine(37, 35, 3, RED);
  display.drawFastHLine(31, 32, 3, RED);
  display.drawFastHLine(26, 29, 3, RED);
  display.drawFastVLine(24, 26, 3, RED);
  display.drawPixel(39, 36, RED);
  display.drawPixel(33, 33, RED);
  display.drawPixel(28, 30, RED);
  display.drawPixel(29, 25, RED);
  display.drawPixel(39, 26, RED);
  delay(500);
}
Bluetooth LE ServiceJava
A snippet of the Android code
package prov2.flip;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import java.util.List;
import java.util.UUID;

public class BLEService extends Service {
    private final static String TAG = BLEService.class.getSimpleName();

    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private String mBluetoothDeviceAddress;
    private BluetoothGatt mBluetoothGatt;
    private int mConnectionState = STATE_DISCONNECTED;

    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    public final static String ACTION_GATT_CONNECTED =
            "prov2.flip.ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED =
            "prov2.flip.ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED =
            "prov2.flip.ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE =
            "prov2.flip.ACTION_DATA_AVAILABLE";
    public final static String EXTRA_DATA =
            "prov2.flip.EXTRA_DATA";
    public final static String DEVICE_DOES_NOT_SUPPORT_UART =
            "prov2.flip.DEVICE_DOES_NOT_SUPPORT_UART";

    public static final UUID TX_POWER_UUID = UUID.fromString("00001804-0000-1000-8000-00805f9b34fb");
    public static final UUID TX_POWER_LEVEL_UUID = UUID.fromString("00002a07-0000-1000-8000-00805f9b34fb");
    public static final UUID CCCD = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    public static final UUID FIRMWARE_REVISON_UUID = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
    public static final UUID DIS_UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
    public static final UUID RX_SERVICE_UUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
    public static final UUID RX_CHAR_UUID = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
    public static final UUID TX_CHAR_UUID = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");


    // Implements callback methods for GATT events that the app cares about.  For example,
    // connection change and services discovered.
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            String intentAction;

            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(TAG, "Connected to GATT server.");
                // Attempts to discover services after successful connection.
                Log.i(TAG, "Attempting to start service discovery:" +
                        mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.i(TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.w(TAG, "mBluetoothGatt = " + mBluetoothGatt );

                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            } else {
                Log.w(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic characteristic,
                                         int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    };

    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);

        // This is special handling for the Heart Rate Measurement profile.  Data parsing is
        // carried out as per profile specifications:
        // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
        if (TX_CHAR_UUID.equals(characteristic.getUuid())) {

            // Log.d(TAG, String.format("Received TX: %d",characteristic.getValue() ));
            intent.putExtra(EXTRA_DATA, characteristic.getValue());
        } else {

        }
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    public class LocalBinder extends Binder {
        BLEService getService() {
            return BLEService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // After using a given device, you should make sure that BluetoothGatt.close() is called
        // such that resources are cleaned up properly.  In this particular example, close() is
        // invoked when the UI is disconnected from the Service.
        close();
        return super.onUnbind(intent);
    }

    private final IBinder mBinder = new LocalBinder();

    /**
     * Initializes a reference to the local Bluetooth adapter.
     *
     * @return Return true if the initialization is successful.
     */
    public boolean initialize() {
        // For API level 18 and above, get a reference to BluetoothAdapter through
        // BluetoothManager.
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                Log.e(TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }

        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }

        return true;
    }

    /**
     * Connects to the GATT server hosted on the Bluetooth LE device.
     *
     * @param address The device address of the destination device.
     *
     * @return Return true if the connection is initiated successfully. The connection result
     *         is reported asynchronously through the
     *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
     *         callback.
     */
    public boolean connect(final String address) {
        if (mBluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        // Previously connected device.  Try to reconnect.
        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
                && mBluetoothGatt != null) {
            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                mConnectionState = STATE_CONNECTING;
                return true;
            } else {
                return false;
            }
        }

        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            Log.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        // We want to directly connect to the device, so we are setting the autoConnect
        // parameter to false.
        mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
        Log.d(TAG, "Trying to create a new connection.");
        mBluetoothDeviceAddress = address;
        mConnectionState = STATE_CONNECTING;
        return true;
    }

    /**
     * Disconnects an existing connection or cancel a pending connection. The disconnection result
     * is reported asynchronously through the
     * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
     * callback.
     */
    public void disconnect() {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.disconnect();
        // mBluetoothGatt.close();
    }

    /**
     * After using a given BLE device, the app must call this method to ensure resources are
     * released properly.
     */
    public void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        Log.w(TAG, "mBluetoothGatt closed");
        mBluetoothDeviceAddress = null;
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }

    /**
     * Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
     * asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
     * callback.
     *
     * @param characteristic The characteristic to read from.
     */
    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.readCharacteristic(characteristic);
    }

    /**
     * Enables or disables notification on a give characteristic.
     *
     * @param characteristic Characteristic to act on.
     * @param enabled If true, enable notification.  False otherwise.
     */
    /*
    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
                                              boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
                    UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
        }
    }*/

    /**
     * Enable TXNotification
     *
     * @return
     */
    public void enableTXNotification()
    {
    	/*
    	if (mBluetoothGatt == null) {
    		showMessage("mBluetoothGatt null" + mBluetoothGatt);
    		broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
    		return;
    	}
    		*/
        BluetoothGattService RxService = mBluetoothGatt.getService(RX_SERVICE_UUID);
        if (RxService == null) {
            showMessage("Rx service not found!");
            broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
            return;
        }
        BluetoothGattCharacteristic TxChar = RxService.getCharacteristic(TX_CHAR_UUID);
        if (TxChar == null) {
            showMessage("Tx charateristic not found!");
            broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
            return;
        }
        mBluetoothGatt.setCharacteristicNotification(TxChar,true);

        BluetoothGattDescriptor descriptor = TxChar.getDescriptor(CCCD);
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        mBluetoothGatt.writeDescriptor(descriptor);

    }

    public void writeRXCharacteristic(byte[] value)
    {


        BluetoothGattService RxService = mBluetoothGatt.getService(RX_SERVICE_UUID);
        showMessage("mBluetoothGatt null"+ mBluetoothGatt);
        if (RxService == null) {
            showMessage("Rx service not found!");
            broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
            return;
        }
        BluetoothGattCharacteristic RxChar = RxService.getCharacteristic(RX_CHAR_UUID);
        if (RxChar == null) {
            showMessage("Rx charateristic not found!");
            broadcastUpdate(DEVICE_DOES_NOT_SUPPORT_UART);
            return;
        }
        RxChar.setValue(value);
        boolean status = mBluetoothGatt.writeCharacteristic(RxChar);

        Log.d(TAG, "write TXchar - status=" + status);
    }

    private void showMessage(String msg) {
        Log.e(TAG, msg);
    }
    /**
     * Retrieves a list of supported GATT services on the connected device. This should be
     * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
     *
     * @return A {@code List} of supported services.
     */
    public List<BluetoothGattService> getSupportedGattServices() {
        if (mBluetoothGatt == null) return null;

        return mBluetoothGatt.getServices();
    }
}
flip
Android app and Bluetooth LE code for interacting with Arduino Micro

Comments

Team Flip

10868106 10205824540120570 145012886772832874 n
Tessira Crawford
  • 3 projects
  • 5 followers
Profile pic
Corey Short
  • 3 projects
  • 8 followers
Img 3336 (2) tgy9fmancy
Sofia Dewar
  • 3 projects
  • 3 followers
Profpic
Christian Le
  • 2 projects
  • 3 followers
Default
cecile basnage
  • 3 projects
  • 5 followers

Published on

March 22, 2015

Members who respect this project

Bs1

and 2 others

See similar projects
you might like

Similar projects you might like

Siri and Google Now home automation

Project in progress by Andres Santos

  • 15,108 views
  • 3 comments
  • 20 respects

Habitatt

Project tutorial by 5 developers

  • 11,163 views
  • 2 comments
  • 34 respects

Sole Searching

Project in progress by 5 developers

  • 8,214 views
  • 13 comments
  • 14 respects

Arduino Micro w/ 3 sensors and color LCD readout

Project in progress by Mike Strand

  • 3,859 views
  • 0 comments
  • 6 respects

Chatty Coasters

Project tutorial by Avocados unLtd.

  • 2,365 views
  • 1 comment
  • 4 respects

MAQ-10 (An Intellectual Maritime Boundary Monitor)

Project in progress by 3 developers

  • 2,419 views
  • 0 comments
  • 10 respects
Add projectSign up / Login