49-713 Designing for the Internet of Things
· 26 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
QT the cutie is here to cheer you up!
QT is an ambient device whose specialty is emoting super cuteness! Like many kawaii characters, QT has the ability to turn a frown upside down, whatever your mood. The device is loosely modeled after a young, hungry bunny. As soon as QT finds out that you're offering her vegetables, she gets very excited - buzzing back and forth in an arc, turning her head, coyly running away and hiding, and glowing her eyes.
Building QT required an immense coordinated effort. Tongtong focused on high level behavior mapping, storyboarding, and vegetable bait design. Nick built out the electronic end of our project, with a special emphasis on ensuring that the servos would run simultaneously at the proper RPMs. Reggie dedicated himself to designing, printing, assembling, and painting QT.
/*
* QT
* Description:
* Author: Nicholas Stone
* Date: 1/29/2017
* Version: 1
*/
const int motor1Pin = D3; // H-bridge leg 1
const int motor2Pin = D4; // H-bridge leg 2
const int enablePin = D5; // H-bridge enable pin
const int phototransPin = A0;
int photoSampleRate = 100;
int light = 0;
int dcMotorStatus = 0;
const int photoLightThres = 2000;
const int bodyLoopCounter = 10;
void setup() {
Serial.begin(9600);
// set all the other pins you're using as outputs:
pinMode(motor1Pin, OUTPUT);
pinMode(motor2Pin, OUTPUT);
pinMode(enablePin, OUTPUT);
//pinMode(phototransPin,INPUT);
// set enablePin high so that motor can turn on:
digitalWrite(enablePin, HIGH);
}
//If switch is high, turn the motor one way by taking one H-bridge pin high and the other low.
//If the switch is low, reverse the direction by reversing the states of the two H-bridge pins.
void loop() {
int i = 0;
light = analogRead(phototransPin);
while(light<photoLightThres) {
if(dcMotorStatus==0) {
digitalWrite(enablePin, HIGH);
dcMotorStatus = 1;
}
while(i<bodyLoopCounter && light<photoLightThres) {
if(i==0){
digitalWrite(motor1Pin, LOW); // set leg 1 of the H-bridge low
digitalWrite(motor2Pin, HIGH); // set leg 2 of the H-bridge high
}
i++;
light = analogRead(phototransPin);
delay(photoSampleRate);
Serial.print("CW Counter Value: ");
Serial.println(i);
}
while(i<2*bodyLoopCounter && light<photoLightThres) {
if(i==bodyLoopCounter){
digitalWrite(motor1Pin, HIGH); // set leg 1 of the H-bridge high
digitalWrite(motor2Pin, LOW); // set leg 2 of the H-bridge low
}
i++;
light = analogRead(phototransPin);
delay(photoSampleRate);
Serial.print("CCW Counter Value: ");
Serial.println(i);
}
if(i==2*bodyLoopCounter && light<photoLightThres){
i = 0;
}
}
if(dcMotorStatus==1)
{
dcMotorStatus = 0;
digitalWrite(enablePin, LOW);
}
Serial.print("Light Value: ");
Serial.println(analogRead(phototransPin));
delay(photoSampleRate);
}
Click to Expand
/*
* Project: QT
* Description: A bunny that responds to its master
* Author: Nicholas Stone
* Date: 1/29/2017
* Version: 2
*/
// H-bridge
const int motor1Pin = D3; // leg 1
const int motor2Pin = D4; // leg 2
const int enablePin = D5; // enable pin
// Photoresistor
const int photoPin = A0;
int photoSampleRate = 100;
int light = 0;
// Servo Motor for the head
Servo headServo;
const int headServoPin = D0;
int headServoPos = 10; // avoid the 0/180 poles
//Number of DC cycles per 180 degrees
const int bodyLoopCounter = 10;
const int photoLightThres = 2000;
void setup() {
Serial.begin(9600);
//H-bridge
pinMode(motor1Pin, OUTPUT);
pinMode(motor2Pin, OUTPUT);
pinMode(enablePin, OUTPUT);
//set headServo initial angle
headServo.attach(headServoPin);
headServo.write(10);
// allow motor to turn on if needed:
digitalWrite(enablePin, HIGH);
}
void loop() {
int i = 0;
light = analogRead(photoPin);
//loop when no light, ie veggie present
while(light<photoLightThres) {
//change code state of motor
if(digitalRead(enablePin)==LOW)) {
digitalWrite(enablePin, HIGH);
//dcMotorStatus = 1;
}
while(i<bodyLoopCounter && light<photoLightThres) {
if(i==0){
digitalWrite(motor1Pin, LOW); // set leg 1 of the H-bridge low
digitalWrite(motor2Pin, HIGH); // set leg 2 of the H-bridge high
}
i++;
light = analogRead(photoPin);
delay(photoSampleRate);
Serial.print("CW Counter Value: ");
Serial.println(i);
}
while(i<2*bodyLoopCounter && light<photoLightThres) {
if(i==bodyLoopCounter){
digitalWrite(motor1Pin, HIGH); // set leg 1 of the H-bridge high
digitalWrite(motor2Pin, LOW); // set leg 2 of the H-bridge low
}
// turn head aroudn
if(i>=bodyLoopCounter*1.5 && i>=(bodyLoopCounter*1.5)+1) {
headServoPos = 170;
headServo.write(headServoPos);
}
i++;
light = analogRead(photoPin);
delay(photoSampleRate);
Serial.print("CCW Counter Value: ");
Serial.println(i);
}
if(i==2*bodyLoopCounter && light<photoLightThres){
i = 0;
headServoPos = 25;
headServo.write(headServoPos);
delay(1000);
headServoPos = 10;
headServo.write(headServoPos);
}
}
if(digitalRead(enablePin)==HIGH)
{
digitalWrite(enablePin, LOW);
}
Serial.print("Light Value: ");
Serial.println(analogRead(photoPin));
delay(photoSampleRate);
}
Click to Expand
/*
* Project: QT
* Description: A bunny that responds to its master
* Author: Nicholas Stone
* Date: 1/29/2017
* Version: 3
*/
int veggiePresent = 0;
// H-bridge
// const int motor1Pin = D3; // leg 1
// const int motor2Pin = D4; // leg 2
// const int enablePin = D5; // enable pin
// Servo Motor for the head
int servoDelay = 100;
Servo headServo;
const int headServoPin = D0;
int headServoPos = 10; // avoid the 0/180 poles
// Servo body for driving the body
Servo bodyServo;
const int bodyServoPin = D1;
//value of continuous servo that causes it to remain static
int bodyServoStatic = 92;
//Number of DC cycles per 180 degrees
const int bodyLoopCounter = 20;
// const int photoLightThres = 2000;
static const int bodyForwardSpeedArray[] = {
180,180,180,180,
160,
140,
120,
110,110,110,
120,120,
130,
140,140,140,140,140,140,140
};
void setup() {
Serial.begin(9600);
// Thermo Subscription
Particle.subscribe("diotQTcarrot", foodStatus);
//H-bridge
// pinMode(motor1Pin, OUTPUT);
// pinMode(motor2Pin, OUTPUT);
// pinMode(enablePin, OUTPUT);
// allow motor to turn on if needed:
// digitalWrite(enablePin, HIGH);
//set Servos initial angle
headServo.attach(headServoPin);
headServo.write(10);
bodyServo.attach(bodyServoPin);
}
void loop() {
int i = 0;
//loop when veggie present
while(veggiePresent==1) {
//change code state of motor
if(digitalRead(enablePin)==LOW) {
digitalWrite(enablePin, HIGH);
}
while(i<bodyLoopCounter && veggiePresent==1) {
/*if(i==0){
digitalWrite(motor1Pin, LOW); // set leg 1 of the H-bridge low
digitalWrite(motor2Pin, HIGH); // set leg 2 of the H-bridge high
}*/
bodyServo.write(bodyForwardSpeedArray[i])
delay(servoDelay);
Serial.print("CW Counter Value: ");
Serial.println(i);
i++;
}
while(i<2*bodyLoopCounter && veggiePresent == 1) {
/*if(i==bodyLoopCounter){
digitalWrite(motor1Pin, HIGH); // set leg 1 of the H-bridge high
digitalWrite(motor2Pin, LOW); // set leg 2 of the H-bridge low
//bodyServo.write(0);
}*/
// turn head around
if(i>=bodyLoopCounter*1.5 && i>=(bodyLoopCounter*1.5)+1) {
headServoPos = 170;
headServo.write(headServoPos);
}
bodyServo.write(0);
delay(servoDelay);
Serial.print("CCW Counter Value: ");
Serial.println(i);
i++;
}
if(i==2*bodyLoopCounter && veggiePresent==1){
i = 0;
headServoPos = 25;
headServo.write(headServoPos);
delay(servoDelay*10);
headServoPos = 10;
headServo.write(headServoPos);
}
}
if(digitalRead(enablePin)==HIGH)
{
digitalWrite(enablePin, LOW);
bodyServo.write(bodyServoStatic);
}
}
//trigger presence of veggie from event publish by other photon
void foodStatus(const char *event,const char *data) {
if(strcmp(data, "foundVegetable")){
Serial.println("foundVegetable");
veggiePresent = 1;
return;
}
if(strcmp(data, "removeVegetable")) {
Serial.println("removeVegetable");
veggiePresent = 0;
return;
}
return;
}
Click to Expand
/*
* Project: QT
* Description: A bunny that responds to its master
* Author: Nicholas Stone
* Date: 1/29/2017
* Version: 4
*/
int veggiePresent = 0;
//LED
const int ledOnePin = D2;
const int ledTwoPin = D3;
int brightness = 0;
int fadeAmount = 20;
// H-bridge
// const int motor1Pin = D3; // leg 1
// const int motor2Pin = D4; // leg 2
//const int enablePin = D5; // enable pin
int motionStatus = 0;
// Servo Motor for the head
int servoDelay = 100;
Servo headServo;
const int headServoPin = D0;
int headServoPos = 10; // avoid the 0/180 poles
// Servo body for driving the body
Servo bodyServo;
const int bodyServoPin = D1;
//value of continuous servo that causes it to remain static
int bodyServoStatic = 93;
//Number of DC cycles per 180 degrees
const int bodyLoopCounter = 50;
int i = 0;
static const int bodyForwardSpeedArray[] = {
180,180,180,180,180,180,180,180,180,180,180,172,164,157,149,141,134,126,118,110,103,95,95,95,95,95,
95,95,96,96,97,98,103,107,116,130,130,128,125,121,113,102,95,95,95,45,45,45,135,135,135
};
static const int bodyBackwardSpeedArray[] = {
0,0,0,0,0,0,0,0,0,0,0,8,16,23,31,39,46,54,62,70,77,85,85,85,85,85,85,85,84,84,83,82,77,73,64,50,50,
52,55,59,67,78,85,85,85,135,135,135,45,45,45
};
void setup() {
Serial.begin(9600);
// Thermo Subscription
Particle.subscribe("diotQTcarrot", foodStatus);
//H-bridge
// pinMode(motor1Pin, OUTPUT);
// pinMode(motor2Pin, OUTPUT);
//pinMode(enablePin, OUTPUT);
// allow motor to turn on if needed:
// digitalWrite(enablePin, HIGH);
//LED
pinMode(ledOnePin,OUTPUT);
pinMode(ledTwoPin,OUTPUT);
//set Servos initial angle
headServo.attach(headServoPin);
headServo.write(10);
bodyServo.attach(bodyServoPin);
}
void loop() {
//int i = 0;
//loop when veggie present
while(veggiePresent==1) {
//change code state of motor
if(motionStatus==0) {
motionStatus = 1;
}
while(i<bodyLoopCounter && veggiePresent==1) {
/*if(i==0){
digitalWrite(motor1Pin, LOW); // set leg 1 of the H-bridge low
digitalWrite(motor2Pin, HIGH); // set leg 2 of the H-bridge high
}*/
bodyServo.write(bodyForwardSpeedArray[i]);
delay(servoDelay);
Serial.print("CW Counter Value: ");
Serial.println(i);
glowLed();
i++;
}
while(i<2*bodyLoopCounter && veggiePresent == 1) {
/*if(i==bodyLoopCounter){
digitalWrite(motor1Pin, HIGH); // set leg 1 of the H-bridge high
digitalWrite(motor2Pin, LOW); // set leg 2 of the H-bridge low
//bodyServo.write(0);
}*/
// turn head around
if(i>=bodyLoopCounter*1.5 && i>=(bodyLoopCounter*1.5)+1) {
headServoPos = 170;
headServo.write(headServoPos);
}
bodyServo.write(bodyBackwardSpeedArray[i-bodyLoopCounter]);
delay(servoDelay);
Serial.print("CCW Counter Value: ");
Serial.println(i);
glowLed();
i++;
}
if(i==2*bodyLoopCounter && veggiePresent==1){
//end of loop
i = 0;
headServoPos = 25;
headServo.write(headServoPos);
delay(servoDelay*10);
headServoPos = 10;
headServo.write(headServoPos);
}
}
if(motionStatus == 1)
{
motionStatus == 0;
bodyServo.write(bodyServoStatic);
//turn off LEDs
brightness = 0;
analogWrite(ledOnePin, brightness);
analogWrite(ledTwoPin, brightness);
}
}
//trigger presence of veggie from event publish by other photon
void foodStatus(const char *event,const char *data) {
if(strcmp(data, "foundVegetable")){
Serial.println("foundVegetable");
veggiePresent = 1;
return;
}
if(strcmp(data, "removeVegetable")) {
Serial.println("removeVegetable");
veggiePresent = 0;
return;
}
return;
}
void glowLed() {
analogWrite(ledOnePin, brightness);
analogWrite(ledTwoPin, brightness);
brightness = brightness + fadeAmount;
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount;
}
}
Click to Expand
const int photoResistor = A0;
const int photoSampleRate = 100;
const int photoDiff = 200;
int light = 0;
int firstLight = 0;
int lightStatus = 0; // 0 = no vegetable, 1 = vegetable
void setup () {
Serial.begin(9600);
Particle.variable("light", &light, INT);
}
void loop () {
light = analogRead(photoResistor);
if(firstLight==0) {
firstLight = light;
}
if(light < firstLight-photoDiff && lightStatus==0){
Particle.publish("diotQTcarrot", "removeVegetable",1,PUBLIC);
lightStatus=1;
}
if(light >= firstLight-photoDiff && lightStatus==1){
Particle.publish("diotQTcarrot", "foundVegetable",1,PUBLIC);
lightStatus=0;
}
delay(photoSampleRate);
}
Click to Expand
QT Setup
1 Particle Photon
1 5V 180 deg Servo motor
1 5V Continuous Servo motor
2 LEDs (White)
2 220 Ohm Resistors
Wires
Breadboard
QT Outer Enclosure Upper Doom
QT Outer Enclosure Lower Ring
3 Fasteners
3 Wheels
4 Bevel Gears
2 Regular Gears
Inner Chasis
Fork and Steering Column
(Optional)
5V DC Brush Motor with wired H-bridge, replacing Continuous Servo
The Table
1 Particle Photon
1 Plate
1 Stuffed Vegetable (or object)
Box with Top Hole
1 Photoresistor
1 10k Ohm Resistor
Wires
1 Breadboard
A hands-on introductory course exploring the Internet of Things and connected product experiences.
QT the cutie is here to cheer you up!
February 6th, 2017