Things used in this project

Hardware components:
Hexiwear docking bd
NXP Hexiwear
×1
Software apps and online services:
ARM mbed mbed OS and Compiler

Schematics

Hexy Block Diagram
based on an image from http://www.hexiwear.com/hardware/

No document.

Code

main.cppC/C++
Main source code file
/*
 * Hexy, a virtual pet that encourages good decisions! < ^.^ >
 *
 * @IShJR
 * http://ishotjr.com/
 * http://ishotjr.github.io/
 */

#include "mbed.h"
#include "Hexi_OLED_SSD1351.h"  // OLED display driver
#include "FXAS21002.h"          // Gyroscope sensor
#include "OpenSans_Font.h"      // allow font choice
#include "string.h"


#define INACTIVITY_THRESHOLD 60 // seconds

// vibration
DigitalOut vibe(PTB9);

// timer
Timer timer;

// timer value at last "movement" (seconds)
float last_movement = 0;

// SSD1351 OLED driver and text properties
SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); /* (MOSI,SCLK,POWER,CS,RST,DC) */
oled_text_properties_t textProperties = {0};


// update Hexy and debug numbers
void refresh_status(char* hexy_text, char* timer_text, char* movement_text,
                    char* last_movement_text, Color_t hexy_color) {
    char text[20]; // text buffer

    // change font color to green plus use larger font for Hexy
    textProperties.fontColor   = hexy_color;
    textProperties.font        = OpenSans_12x18_Regular;
    textProperties.alignParam   = OLED_TEXT_ALIGN_CENTER;
    //textProperties.background = NULL;
    oled.SetTextProperties(&textProperties);

    // display Hexy at center (actually, offset a fair bit now to make room for debug)
    strcpy(text,hexy_text);
    oled.TextBox((uint8_t *)text,(96-64)/2,(96-18-24)/2,64,18);
        
    // set text properties to grey/regular size for the timer and movement
    textProperties.fontColor = COLOR_GRAY;
    textProperties.font        = OpenSans_10x15_Regular;
    oled.SetTextProperties(&textProperties); 
    
    strcpy(text,movement_text);
    // display RMS in 64px by 16px textbox above last movement
    oled.TextBox((uint8_t *)text,(96-64)/2,96-16-16-16,64,16);  

    strcpy(text,last_movement_text);
    // display last movement time in 64px by 16px textbox above timer
    oled.TextBox((uint8_t *)text,(96-64)/2,96-16-16,64,16);       
            
    strcpy(text,timer_text);
    // display time in 64px by 16px textbox at bottom center
    oled.TextBox((uint8_t *)text,(96-64)/2,96-16,64,16);       
}

// generic "animation" (toggles frame*_text for duration_ms)
void animate(int duration_ms, char* frame1_text, char* frame2_text, 
             bool is_loading, float gyro_rms, bool do_vibrate) {
                    
    char text[20], gyro_rms_text[20], last_movement_text[20]; // text buffers
    Color_t hexy_color;

    for (int i = 0; i < duration_ms; i = i + 500) {    

        // TODO: refactor - lots of duplication here!

        // TODO: note that this means rms is only updated once per duration!
        // (seems to work really well regardless though?!)
        
        // turn red if beyond inactivity threshold
        if ((timer.read() - last_movement) > INACTIVITY_THRESHOLD) {
            hexy_color = COLOR_RED;
        } else {
            hexy_color = COLOR_GREEN;
        }

        if (gyro_rms > 0) {
            sprintf(gyro_rms_text,"%.2f",gyro_rms);            
        } else {
            // placeholder if 0 or negative
            strcpy(gyro_rms_text,"-");    
        }
        
        if (last_movement > 0) {
            sprintf(last_movement_text,"%.2f",last_movement);            
        } else {
            // placeholder if 0 or negative
            strcpy(last_movement_text,"-");    
        }
        
        if (is_loading) {
            strcpy(text,"Loading.. ");    
        } else {
            // format the timer reading
            sprintf(text,"%.2f",timer.read());            
        }

        refresh_status(frame1_text, text, gyro_rms_text, 
                       last_movement_text, hexy_color);
        Thread::wait(250);

        // turn red if beyond inactivity threshold
        if ((timer.read() - last_movement) > INACTIVITY_THRESHOLD) {
            hexy_color = COLOR_RED;
        } else {
            hexy_color = COLOR_GREEN;
        }
        
        // vibrate during second frame if set (not both, i.e. pulse vs. continual)
        if (do_vibrate && ((timer.read() - last_movement) > INACTIVITY_THRESHOLD)) {
            vibe = 1;
        }
        
        if (last_movement > 0) {
            sprintf(last_movement_text,"%.2f",last_movement);            
        } else {
            // placeholder if 0 or negative
            strcpy(last_movement_text,"-");    
        }
        
        if (is_loading) {
            strcpy(text,"Loading...");    
        } else {
            sprintf(text,"%.2f",timer.read());            
        }
        refresh_status(frame2_text, text, gyro_rms_text, 
                       last_movement_text, hexy_color);
        Thread::wait(250);
        vibe = 0; // stop vibration (whether set or not)
    }    
}

// sleepy animation (+vibration)
void hexy_sleep(int duration_ms, bool is_loading, float gyro_rms) {
    animate(duration_ms, "< -_- > ..z", "< -o- > .zZ", is_loading, gyro_rms, true);
}

// happy animation
void hexy_happy(int duration_ms, bool is_loading, float gyro_rms) {
    animate(duration_ms, "< o_o >", "< ^.^ >", is_loading, gyro_rms, false);
}

// select animation based on movement
void hexy_update(int duration_ms, bool is_loading, float gyro_rms) {
    if (gyro_rms > 10) {
        // TODO: ^^^ adjust/smooth?
        // (seems to work amazingly well without though...?)
        
        // yay, movement!
        hexy_happy(500, false, gyro_rms);

        // update last movement
        last_movement = timer.read();
    } else {
        // boo, no movement!
        hexy_sleep(500, false, gyro_rms);        
    }
}

// setup and loop
int main() {
    char text[20]; // text buffer
    // TODO: do something about overflow after half an hour, e.g. switch to use RTC?

    // FXAS21002 pin connections for Hexiwear
    FXAS21002 gyro(PTC11,PTC10);
    // storage for the data from the gyro
    float gyro_data[3];  
    float gyro_rms=0.0;

    gyro.gyro_config();
        
    oled.GetTextProperties(&textProperties);    

     // center align
    textProperties.alignParam   = OLED_TEXT_ALIGN_CENTER;

    // turn on the OLED backlight
    oled.DimScreenON();
    
    // fills the screen with solid black
    oled.FillScreen(COLOR_BLACK);

    // display app title at top center
    strcpy((char *) text,"Hexy");
    oled.TextBox((uint8_t *)text,(96-48)/2,4,48,16);
    
    // give the user a chance to get acclimated
    hexy_happy(2000, true, -1);
    
    // start timer
    timer.start();
    last_movement = timer.read();

    while (true) {
        // poll gyro and update Hexy forever!
        gyro.acquire_gyro_data_dps(gyro_data);
        gyro_rms = sqrt(((gyro_data[0]*gyro_data[0])+(gyro_data[1]*gyro_data[1])+(gyro_data[2]*gyro_data[2]))/3);
        hexy_update(500, false, gyro_rms);
    }
}


    
    
hexy-mvp Mercurial repository
Import into the mbed Compiler or CLI to build!

Credits

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Similar projects you might like

Offline Speech Processing
Intermediate
  • 2,277
  • 18

Protip

Create your very own hotwords like "Alexa," "Ok Google" and "Hey Cortana," and trigger events just by speaking... without the Internet.

Agricultural flow estimator
Intermediate
  • 319
  • 11

Hey you, small farmer! I Have these camera based sensor to control how much fertilizer is deposited in your plantation

Sketch Drive Car
Intermediate
  • 2,125
  • 46

Full instructions

This project aims at controlling a car through a trajectory traced by the user on a screen running windows or android

Kinetis FlexIO Ultrasonic Radar
Intermediate
  • 1,164
  • 22

Full instructions

360° Ultrasonic Radar for DIY applications, with self written FlexIO driver.

Build an Air Mouse with NXP K82F and FlexIO
Intermediate
  • 609
  • 11

Full instructions

Build next-gen gesture pointing device ideal for 3D CAD design or SmartTV control. Compatible with anything that accepts a USB mouse.

Make Javascript Apps for Hexiwear 101
Intermediate
  • 880
  • 18

Protip

This project unleashes a javascript mobile app template for reading data off the NXP Hexiwear. If many like it, we'll make more of them!

ProjectsCommunitiesTopicsContestsLiveAppsBetaFree StoreBlogAdd projectSign up / Login
Feedback