Project tutorial

Tedduino 101 © GPL3+

A cuddly, interactive IoT buddy that teaches, comforts and empowers children.

  • 882 views
  • 0 comments
  • 3 respects

Components and supplies

Necessary tools and machines

Sewing Machine

Apps and online services

About this project

Introduction

About a year ago we picked up an Echo and began kitting our house out with Wemo switches and plugs. It's soooo nice to be able to tell Alexa to turn the lights off from the warmth of bed. This is where our 3 year old daughter comes into the picture. Too short to reach the light switches and lacking the vernacular to direct Alexa, but determined enough to keep trying. That's when I realized, the same tech that's made our lives convenient as adults can empower our children to use the same devices. At the same time, we can build a companion that grows with them. A toy that can be programmed with different games every week, or evolve into a study partner. Eventually, a friend she will one day learn to program herself, bridging not only the gap between children and smart homes, but driving interest in technology through a fluffy pal that matures in parallel.

This is where the Seeed Grove Starter Kit is ideal. It comes with a plethora of fun I/O devices and the potential of adding many more. Swapping in something new (like a distance sensor) is as simple as plugging in a cable.

To drive the shield I'm using the new Arduino 101 (Genuino in Canada & Europe). Much like the Uno, but with the notable additions of a gyroscope, accelerometer and bluetooth.

Finally, to control the Wemo's from the Arduino I'm using an old Android phone (S4 Active) using Evothings Studio, a cordova based mobile ide that lets you code apps using HTML5 and JS. This will pair with the 101 over bluetooth and control the Wemo's via the Maker IFTTT channel.

Bill of Materials

Hardware

  • Sewing Machine/Fabric (or use an existing toy)

Software

Instructions

Arduino/Grove

Place the Grove Base Shield onto the Arduino, then attach the included sensors and outputs to match the diagram below.

Install the Arduino IDE according to the instructions online. With the software running plug in the Arduino 101 board with the usb cable. In the IDE go to Tools>Board and choose "Arduino/Genuino 101". Then under Tools>Port select the port your board is listed by, ex. COM3(Arduino/Genuino 101).

Clone, download or copy the code from GitHub and open /arduino/Tedduino/Tedduino.ino

/* 
* Tedduino.ino 
* @author : Justin Revelstoke 
* @date : 3/25/2017 
* @description : Arduino code for BLE connection and Grove Shield I/O. 
*                Displays a menu over RGB LCD offering sensor data and 
*                an example game.                 
*/ 
#include <Wire.h> 
#include <CurieBLE.h> 
#include "CurieIMU.h" 
#include "config.h" 
BLEPeripheral blePeripheral; 
BLEService bleService(serviceUUID); 
BLECharacteristic bleCharacteristic(characteristicUUID, BLERead | BLENotify, 2); 
#include "rgb_lcd.h" 
rgb_lcd lcd; 
const int B = 3975; 
const int pinTouch = 2; 
const int pinBuzzer = 3; 
const int pinButton = 4; 
const int pinVibe = 5; 
const int pinLED = 13; 
const int pinSound = A0; 
const int pinLight = A1; 
const int pinTemp = A2; 
const int pinPot = A3; 
int menu = 0; 
int previousButtonState = 0; 
int length = 15; // the number of notes 
char notes[] = "ccggaagffeeddc "; // a space represents a rest 
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 }; 
int tempo = 300; 
float aix, aiy, aiz;   // accelerometer values 
float gix, giy, giz;   // gyroscope values 
void setup() { 
 Serial.begin(9600); 
 lcd.begin(16, 2); 
 lcd.setCursor(0, 0); 
 pinMode(pinLED, OUTPUT); 
 pinMode(pinPot, INPUT); 
 pinMode(pinTouch, INPUT); 
 pinMode(pinButton, INPUT); 
 blePeripheral.setLocalName(bleServiceName); 
 blePeripheral.setAdvertisedServiceUuid(bleService.uuid()); 
 blePeripheral.addAttribute(bleService); 
 blePeripheral.addAttribute(bleCharacteristic); 
 const unsigned char bleCharArray[2] = { 0, (char)1 }; 
 bleCharacteristic.setValue(bleCharArray, 2); 
 blePeripheral.begin(); 
 CurieIMU.begin(); 
 CurieIMU.setGyroRate(25); 
 CurieIMU.setAccelerometerRate(25); 
 CurieIMU.setAccelerometerRange(2); 
 CurieIMU.setGyroRange(250); 
} 
void loop() { 
 printGyroAccel(); 
 digitalWrite(pinLED, LOW);   
 breath(REG_RED); 
 breath(REG_GREEN); 
 breath(REG_BLUE); 
 BLECentral central = blePeripheral.central(); 
 if (central) { 
   Serial.print("Connected to central: "); 
   Serial.println(central.address()); 
   while (central.connected()) { 
     displayMenu(); 
     delay(100); 
   } 
 } 
 delay(100); 
} 
void nextMenu() {   
 if (menu == 5) { 
   menu = 0; 
 } 
 else { 
   menu++; 
 } 
} 
void displayMenu() { 
 resetLCD(); 
 int buttonState = digitalRead(pinButton);  
 int touchState = digitalRead(pinTouch); 
 buttonState = buttonState | touchState;   
 if (previousButtonState != buttonState) { 
   if (buttonState == 1) { 
     const unsigned char bleCharArray[2] = { 0, (char)1 }; 
     bleCharacteristic.setValue(bleCharArray, 2); 
     nextMenu(); 
     delay(1000); 
   } 
   else {       
     const unsigned char bleCharArray[2] = { 0, (char)0 }; 
     bleCharacteristic.setValue(bleCharArray, 2); 
   } 
 } 
 delay(100); 
 previousButtonState = buttonState; 
 if (menu == 0) { 
   printSound(); 
 } 
 else if (menu == 1) { 
   printLight(); 
 } 
 else if (menu == 2) { 
   printTemp(); 
 } 
 else if (menu == 3) { 
   printVibe(); 
 } 
 else if (menu == 4) { 
   printPot(); 
 } 
 else if (menu == 5) { 
   nightMode(); 
 } 
 else if (menu == 6) { 
   printGyroAccel(); 
 } 
 else { 
   lcd.print("Error"); 
 } 
} 
void resetLCD() { 
 lcd.clear(); 
 lcd.setCursor(0, 0); 
} 
void printGyroAccel() { 
 CurieIMU.readAccelerometerScaled(aix, aiy, aiz); 
 CurieIMU.readGyroScaled(gix, giy, giz); 
 //CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz); 
 lcd.print(aix); 
 lcd.print(' '); 
 lcd.print(aiy); 
 lcd.print(' '); 
 lcd.print(aiz); 
 lcd.setCursor(0, 1); 
 lcd.print(gix); 
 lcd.print(' '); 
 lcd.print(giy); 
 lcd.print(' '); 
 lcd.print(giz); 
 delay(100); 
 resetLCD(); 
} 
int getSound() { 
 int sensorValue = analogRead(pinSound); 
 return sensorValue; 
} 
void printSound() { 
 int sensorValue = getSound(); 
 lcd.print("Sound:"); 
 if (sensorValue > 0) { 
   for (int i = 0; i < round(sensorValue/100); i++) { 
     lcd.print(">"); 
   } 
 }   
} 
int getLight() { 
 int sensorValue = analogRead(pinLight); 
 return sensorValue; 
} 
void printLight() { 
 // range 0 - 1023 
 int sensorValue = getLight(); 
 lcd.print("Light:"); 
 if (sensorValue > 0) { 
   for (int i = 0; i < round(sensorValue/100); i++) { 
     lcd.print(">"); 
   } 
 }   
} 
int getTemp() { 
 int sensorValue = analogRead(pinTemp); 
 float resistance = (float)(1023-sensorValue)*10000/sensorValue; 
 int temperature = 1/(log(resistance/10000)/B+1/298.15)-273.15; 
 return temperature; 
} 
void printTemp() { 
 lcd.print("Temp:"); 
 lcd.print(getTemp()); 
 lcd.print("F"); 
} 
int getPot() {   
 return analogRead(pinPot); 
} 
void printPot() { 
 lcd.print("Pot:"); 
 lcd.print(getPot()); 
} 
int getVibe() {   
 return digitalRead(pinVibe); 
} 
void printVibe() { 
 lcd.print("Vibe:"); 
 lcd.print(getVibe()); 
} 
void nightMode() { 
 bool warm = false; 
 bool dark = false; 
 bool quiet = false; 
 if (getTemp() >= 50) { 
   lcd.print("Warm "); 
   warm = true; 
 } 
 else { 
   lcd.print("Cold "); 
 } 
 if (getLight() == 0) { 
   lcd.print("Dark "); 
   dark = true; 
 } 
 else { 
   lcd.print("Light "); 
 } 
 if (getSound() < 100) { 
   lcd.print("Quiet "); 
   quiet = true; 
 } 
 else { 
   lcd.print("Loud "); 
 } 
 if (warm && dark && quiet) { 
   playSong(); 
 } 
} 
void playSong() {   
 for (int i = 0; i < length; i++) { 
   if (notes[i] == ' ') { 
     delay(beats[i] * tempo); // rest 
   } 
   else { 
     playNote(notes[i], beats[i] * tempo); 
   } 
   // pause between notes 
   delay(tempo / 2); 
 } 
} 
void playTone(int tone, int duration) { 
 for (long i = 0; i < duration * 1000L; i += tone * 2) { 
   digitalWrite(pinBuzzer, HIGH); 
   delayMicroseconds(tone); 
   digitalWrite(pinBuzzer, LOW); 
   delayMicroseconds(tone); 
 } 
} 
void playNote(char note, int duration) { 
 char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' }; 
 int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 }; 
 // play the tone corresponding to the note name 
 for (int i = 0; i < 8; i++) { 
   if (names[i] == note) { 
     playTone(tones[i], duration); 
   } 
 } 
} 
void breath(unsigned char color) 
{ 
   for(int i=0; i<255; i++) 
   { 
       lcd.setPWM(color, i); 
       delay(5); 
   } 
   delay(500); 
   for(int i=254; i>=0; i--) 
   { 
       lcd.setPWM(color, i); 
       delay(5); 
   } 
   delay(500); 
} 

Be sure config.h is in the same directory

/* 
* config.h 
* @author : Justin Revelstoke 
* @date : 3/25/2017 
* @description : Configuration  
*/ 
// You're device will appear in bluetooth connection lists under this name 
#define bleServiceName "Tedduino" 
#define serviceUUID "180D" 
#define characteristicUUID "2A37" 

Click the Upload button in the Arduino IDE, the console should read :

Starting download script...
SUCCESS: Sketch will execute in about 5 seconds.

If it worked correctly you should now see the LCD pulsing red, green and blue.

At this point the Arduino is advertising a BLE connection, but has a number of "offline" functions. Pressing the button or touch sensor will rotate through various displays on the LCD showing reading from the attached sensors. There is also a sample "game" which asks you to place the Arduino somewhere light|dark, warm|cold, or quiet|loud. Upon success a song will play :)

Evothings

Now to set up the BLE companion app. If you are interested in learning more about Bluetooth Low Energy I highly recommend this primer from Adafruit. Also, if you want to use the BLE connection without needing to make a web request Blynk is a great way to get connected to your Arduino fast. It just doesn't support the functions I needed over BLE.

So the first thing we need to do is download and install Evothings Studio (version 2.2.0 as of this writing). Be sure to get a cloud token from the download page.

Next, download the Evothings Viewer from the app store.

Type in the connect key from Studio into the Viewer to link them.

Now, from the same repository you cloned earlier open the cordova folder and find the evothings.json file. Click and drag this file into Evothings Studio to create the project. You should now see ...

And if you click "Run", the app should start on your phone

IFTTT Integration

To finalize the Evothings code we'll need to set up a Maker channel in IFTTT. To do this go to IFTTT. Log in or create an account if you don't already have one. Then under "My Applets" click "New Applet". Follow the series of images below to set up your Maker channels. Be sure to copy the key Maker generates for you after it sets up your url. We'll need that for cordova. Create two channels, one with "tedduino_on" as the trigger, the other with "tedduino_off". Choose "Turn On" and "Turn Off" for the Wemo actions accordingly.

If all goes well we should now have two channels and a Maker key. You can test the URLs in a browser (they should look something like http://maker.ifttt.com/trigger/tedduino_off/with/key/{your maker key}).

Putting it all together

Back in the cordova code from GitHub open index.html inside the app folder. Find the line:

var makerKey = '/with/key/INSERT YOUR KEY HERE';

And replace "INSERT YOUR KEY HERE" with your maker channel key. Save and reconnect your Evothings studio to the viewer.

Congrats! At this point you should be able to run the Evothings app and click "Connect". If it successfully connects to the Arduino you can press "Test" and the LCD should stop changing colors. You should also be able to push the Grove button to turn the lights on and off.

If you're handy with a sewing machine I'd recommend designing your own doll. Otherwise you can easily retrofit these parts into an existing one. Just replace the usb cable with the Arduino battery pack. Hot glue is a great way to keep the pieces in place. Have fun with it!

As time goes on and more aspects of our homes are becoming automated I hope more devices like this are made to give our children more independence.

Code

Tedduino
Contains the arduino and cordova code used.

Schematics

Tedduino Grove Shield wiring
Grove/Arduino GPIO connections
tedduino_dX6HwXSODs.fzz

Comments

Similar projects you might like

SMS alerts for arduino 101 BLE

Project tutorial by Alexis Santiago Allende

  • 1,905 views
  • 0 comments
  • 7 respects

Smart Garbage Monitoring System Using Arduino 101

Project tutorial by Technovation

  • 21,403 views
  • 7 comments
  • 32 respects

Arduino 101 BLE App

Project in progress by Alexis Santiago Allende

  • 10,842 views
  • 26 comments
  • 51 respects

Control RGB LED by Dragging – Arduino 101 & App Inventor

Project tutorial by DFRobot and CAVEDU Education

  • 4,459 views
  • 0 comments
  • 13 respects

Arduino 101 BLE Rover

Project tutorial by shadeydave

  • 3,463 views
  • 0 comments
  • 13 respects

Open Data Home Automation - Arduino 101 & App Inventor

Project tutorial by 3 developers

  • 3,237 views
  • 1 comment
  • 11 respects
Add projectSign up / Login