Antipode
Made by Yiming Jiao, Yujin Wu and Sohyun Jin
Made by Yiming Jiao, Yujin Wu and Sohyun Jin
We are going to produce a product could connect people from long diatance to exchange their emotion or some informations.
Created: December 4th, 2023
We propose a system featuring two interconnected liquid timers, symbolizing connection over distance. Each liquid timer is controlled by a servo for rotation, controlled by a handle. To transmit a signal, a user rotates the handle by 180 degrees. One end of the handle has a magnet, and a hall effect detector registers changes in magnetic status, transmitting a signal to an argon device. The argon then activates the servos on both the local and remote liquid timers, causing them to rotate by 180 degrees and the colorful liquid will slowly descend. Simultaneously, a neopixel behind a translucent acrylic adding a subtle visual element to the communication process. Given that the liquid timer's rotation is observable for only two minutes, we explore the use of timed, subtle signals as a means of communication.
We have created a prototype with reed sensor and a magnetic in out argon kit to trigger the system. The reed sensor and a magnetic replace the switch in the previous mock (Homework Dev V). Whenever there is a magnet near the reed sensor, it changes the global variable to 0, and whenever the magnet is faraway, the global variable is set to false. When servo rotate 180 degree whenever there is a change in this global variable.
We've received a significant amount of feedback on enhancing the user experience. For instance, it's noted that the initial instinct upon installation is to rotate the clock instead of exploring the magic wand 🪄. People seem to have a ingrained perception of interacting with a liquid timer. Despite not wanting to enclose it, the reality is that it's becoming more of a display, prompting consideration of using a transparent acrylic. This experience highlights the importance of being more decisive in our design approach.
Another point of feedback relates to the 2-minute replay effect. When person B receives a signal from person A, finding an efficient acknowledgment method is crucial. While replicating the signal could work, it risks interrupting A's previous message. To address this, a suggestion is to repeat the action of touching the snoopy with the magic wand, triggering a color change instead of rotating the timer—a quick way for person A to know their message is received.
Other valuable feedback includes slowing down the rotating speed of the timer and swapping the locations of Snoopy and Woodstock. These insights will be considered for future improvements. Reflecting on our three-week experience, we acknowledge underestimating the time required to design, test, and redesign the mechanical aspects, particularly with 3D printing. Consequently, there was a rush to ensure everything was functioning just two hours before the actual presentation.
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
// -----------------------------------
// Controlling LEDs over the Internet
// -----------------------------------
// First, let's create our "shorthand" for the pins
// Same as in the Blink an LED example:
// led1 is D0, led2 is D7
// Code for neopixels
#include <neopixel.h>
#include "neopixel.h"
#define PIXEL_PIN D3
#define PIXEL_COUNT 16
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
int status = 0; // 0 for default dark, 1 for going to white, 2 for fading to dark
std::array<int, 3> dark = {0, 0, 0};
std::array<int, 3> white = {255, 255, 255};
long lightDuration = 1000 * 10 ;
long fadeDuration = 1000 * 15 ;
long timerStartAt = -1;
// code for servo
Servo servo;
int servoPin = A2;
int switchPin = D5;
int hallPin = A5;
int curSwitchState;
int ledPin = D2;
int servoPos;
int first = 1;
int hallState;
void setup()
{
pinMode( switchPin , INPUT_PULLUP); // sets pin as input
pinMode( hallPin , INPUT_PULLUP); // sets pin as input
pinMode( ledPin , OUTPUT ); // sets pin as output
servo.attach( servoPin );
servo.write(0);
servoPos = 0;
curSwitchState = 0;
Serial.begin( 9600 );
Particle.variable("servoPos", servoPos);
Particle.variable("hallState", hallState);
Particle.variable("buttonState", curSwitchState);
Particle.subscribe("rotate", handleRemoteRotate);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
// Last time, we wanted to continously blink the LED on and off
// Since we're waiting for input through the cloud this time,
// we don't actually need to put anything in the loop
uint32_t getCurrentRGB(int duration, int timeElapsed, std::array<int, 3> prevColor, std::array<int, 3> targetColor) {
int prev_r = prevColor[0];
int prev_g = prevColor[1];
int prev_b = prevColor[2];
int target_r = targetColor[0];
int target_g = targetColor[1];
int target_b = targetColor[2];
int r, g, b; // Declare variables outside the loop
Serial.println(timeElapsed);
if (timeElapsed == 0) {
r = prev_r;
g = prev_g;
b = prev_b;
}
r = map(timeElapsed, 0, duration, prev_r, target_r);
g = map(timeElapsed, 0, duration, prev_g, target_g);
b = map(timeElapsed, 0, duration, prev_b, target_b);
Serial.println( r);
Serial.println( g);
Serial.println( b);
return strip.Color(r, g, b);
}
void loop() {
// handle servo
int newSwitchState;
hallState = analogRead(hallPin);
if (hallState < 3000) {
newSwitchState = 0;
} else {
newSwitchState = 1;
}
Serial.print(hallState);
if( newSwitchState == LOW ){
digitalWrite( ledPin, HIGH);
}else{
digitalWrite( ledPin, LOW);
}
if (curSwitchState != newSwitchState) {
if (curSwitchState == 1) {
Particle.publish("triggerRotate");
rotateServo();
timerStartAt = millis();
status = 1;
curSwitchState = newSwitchState;
} else {
curSwitchState = newSwitchState;
}
}
// handle neoplixels
uint32_t c = strip.Color(0, 0, 0);
long timeNow = millis();
long timeElapsed = timeNow - timerStartAt;
Serial.print( "timeElapsed");
Serial.println( timeElapsed);
if (status == 0) {
// do nothing to change the color
timerStartAt = timeNow;
}else if (status == 1) {
if (timeElapsed <= lightDuration) {
c = getCurrentRGB(lightDuration, timeElapsed, dark, white);
// Particle.publish("status is 1");
} else {
timerStartAt = timeNow;
// Particle.publish("Changing to 2");
timeElapsed = timeNow - timerStartAt;
c = getCurrentRGB(lightDuration, timeElapsed, white, dark);
status = 2;
}
} else if (status == 2) {
if (timeElapsed < fadeDuration) {
c = getCurrentRGB(fadeDuration, timeElapsed, white, dark);
// Particle.publish("status is 2");
} else {
timerStartAt = timeNow;
status = 0;
}
} else {
Particle.publish("error status");
}
for(int i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
// Serial.print( "pixel");
// Serial.println( i);
}
delay(100);
}
// We're going to have a super cool function now that gets called when a matching API request is sent
// This is the ledToggle function we registered to the "led" Particle.function earlier.
int handleRemoteRotate(const char *event, const char *data) {
timerStartAt = millis();
rotateServo();
status = 1;
return 1;
}
int rotateServo() {
if (servoPos == 0) {
servoPos = 180;
servo.write(180);
return 1;
} else if (servoPos == 180) {
servoPos = 0;
servo.write(0);
return 1;
} else {
return -1;
}
}
Click to Expand
Each video below should be expanded to its maximum size.
A hands-on introductory course exploring the Internet of Things and connected product experiences.
We are going to produce a product could connect people from long diatance to exchange their emotion or some informations.