For our Dear Husbands
Collaborative installation project with Sandra Davila. Our project documentation blog.

why:
For those husbands who can’t understand why their wifes suddenly turns to a different person. Also for those wives who are constantly surprised how little they know about their own body, or constantly realize they forget their period again.

Though Sandra and I, we don’t have husbands, we’ve heart a lot of stories between couples: how much headache the poor husbands had in terms of dealing with their emotional (or super emotional) wives, how hard wives could control themselves, how careless couples deal with issues of period and the effects of period and physical and psyclogical cycles, and also how difficult to let our dear husbands remember their wives’ period cycle, and how poor they could smell whether their wives are in the mood of sex or not… in the mood of choclate, or in the mood of fighting … So we want to build a clock to make these invisible things visible and interpretable between couples. When we explained the basic idea, one class-mate said “Something like that could have saved my marriage” haha, maybe a joke. But we want to see how people react to our clock.

what:
The project consist in a wall clock, one handle will be dedicated to track the women’s period and tell the men when the women is getting their period. The other handle is adjustable by the women to set her daily mood of sex. The clock will remember the moment in the cycle of a women and her mood of sex for the next period cycle to display.

how:
The woman will input in a program (in processing) the approximate days that her cycle takes and the fist day of her cycle (the program will do the rest to make the physical clock run according to her input of her cycle). From there on, she will only need to dial her mood of Sex in to the physical clock that is made for tracking. After her fist cycle is over, she could see her mood of sex displayed the next cycle and she can also add more or correct her former dail them so that that will be displayed the next cycle.

in ITP winter show 2007

video: (to be uploaded)

building:

1, getting motors from a typewriter. that's where our motors come.

2, wiring the 2 stepper motors. Both of them areunipolar. The unipolar stepper motor has five or six wires and four coils (actually two coils divided by center connections on each coil). The center connections of the coils are tied together and used as the power connection. They are called unipolar steppers because power always comes in on this one pole. (source: http://www.tigoe.net/pcomp/code/category/code/arduinowiring/51 )

3, connecting the encoder http://www.nubotics.com/support/index.html

4, soldering onto little piece of perfboard to make the plug-in modula on arduino

5, test the encoder, and we got accurate readings: every rotation of the steppers, the encoder increments "62"

6, first version of housing gears, motors and encoder.

6, final version of housing

7, standing up (here is the tricky thing.the gravity made the gears works a little bit different, when moving towards up, like 9 o clock, the pointer stepping may loose steps, so we did re-housing, making it more secure and stable, and checking motors again) DSC02066

8, spray the face and mount onto the clock.

this is the final code in arduino:

// Variables for calculating PERIOD and SEX pointers
//float speedPointer();
//#include <avr/pgmspace.h>
int encoder[108];
//PROGMEM prog_uchar encoder[106];
//prog_uchar encoder[106] PROGMEM;
//unsigned char lastEncoder0Pos;
int displayRead;
int lastEncoder0Pos;
unsigned char encoder0Pos;
int steps;

int timePeriod=120;
int passedDays=15;
int cycleCount;
int gear20=18;
int gear24=96;
int delayRate;
int pointerPos=0;
//int sexPoint=0;
//int reading[107];
int initialSteps;
int delayMillis;
int savedMillis;
int ellapsedMillis;
int displayEncoder;
//int lastEncoder0Pos;
int lastChange;

//Variables for communicating to Processing
int firstByte; // value for Period
int secondByte; // value for Initial Date
int serialInArray[3]; // array for storing 3 bytes as they arrive from processing
int serialCount = 0; // for counting the number of bytes received

// ENCODER Variables
#define encoder0PinA  2
#define encoder0PinB  3
//volatile int encoder0Pos = 0;

// Stepper Motor Variables
int counter=0;
#include <Stepper.h>
//Motor Steps for Motor 1
#define motor1Steps 24     // change this depending on the number of steps
// Steps fo motor 2
#define motor2Steps 20                         // per revolution of your motor
// Pins 4 to 7 for Motor 1
#define motorPin1 8
#define motorPin2 9
#define motorPin3 10
#define motorPin4 11
//Pins 8-11 for Motor 2
#define motorPin5 4
#define motorPin6 5
#define motorPin7 6
#define motorPin8 7
// initialize of the Stepper library:
Stepper myStepper(motor1Steps, motorPin1,motorPin2,motorPin3,motorPin4);
Stepper myStepper2(motor2Steps,motorPin5,motorPin6,motorPin7,motorPin8);

void setup() {
// set the motor speed at 60 RPMS:
myStepper.setSpeed(10);
myStepper2.setSpeed(60);

// Initialize the Serial port:
Serial.begin(9600);
//  myStepper.step(10);

//SETUP FOR ENCODER
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor
attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
Serial.begin (9600);
Serial.println(”start”);                // a personal quirk
savedMillis=millis();
initialSteps=-106.67*passedDays/timePeriod;
delayMillis=9.375*timePeriod;
myStepper2.step(int(initialSteps));

Serial.println(initialSteps);
}

void loop() {
lastChange = millis();

/*
if (Serial.available() > 0) {
// read the most recent byte (which will be from 0 to 255)
if(Serial.read()==65){
timePeriod = Serial.read();
passedDays = Serial.read();
}
}
*/
/*
serialInArray[serialCount] = Serial.read(); // read a byte sent by processing
serialCount++;  // increment number of bytes received
if (serialCount > 2 ) {  // when 3 bytes received
firstByte = serialInArray[1]; // get value for PERIOD
secondByte = serialInArray[2]; // get value for INITIAL DATE
serialCount = 0;
}
*/
//delayMillis=1000*gear20*timePeriod/(gear24*motor2Steps);

// delayMillis=0;
// Serial.println(delayMillis);

//+” “+delayMillis+” “+savedMillis);

ellapsedMillis=millis()-savedMillis;
if(ellapsedMillis>=delayMillis){
// Serial.println(ellapsedMillis);
myStepper2.step(-1);
savedMillis=millis();
pointerPos+=1;
//  if(pointerPos==30){
//    Serial.println(”pointerPos”);
//    Serial.println(pointerPos);
//  }

//encoder[pointerPos]=encoder0Pos;
//encoder0Pos=lastEncoder0Pos;
//Serial.println(pointerPos);
// displayEncoder = pgm_read_byte_near(lastEncoder0Pos);
// Serial.println(displayEncoder);

///////// STEPPER1.STEP()

// lastEncoder0Pos = encoder0Pos;
// note the last time the encoder changed:

//lastEncoder0Pos=encoder[pointerPos];
//   if (encoder0Pos != encoder[pointerPos] && encoder[pointerPos]>0) {
if (encoder[pointerPos]>0)  {
// save the last change in the encoder:
//  if(pointerPos<30){
Serial.println(”encoder[pointerPos]” );
Serial.println(encoder[pointerPos]);
//  }
//   Serial.println(”encoder0Pos”);
//   Serial.println(encoder0Pos, DEC);
//   Serial.println(”lastEncoder0Pos”);
//   Serial.println(lastEncoder0Pos);

steps=int(.375*(-encoder0Pos+encoder[pointerPos]));
Serial.println(steps);
myStepper.step(steps);
}
/*
if(encoder0Pos>lastEncoder0Pos){
steps=int(.375*(64-encoder0Pos+lastEncoder0Pos));
Serial.println(”steps1″);
Serial.println(steps);
// Serial.println(.375*(64-encoder0Pos+encoder[pointerPos]));
}else{
steps=int(.375*(lastEncoder0Pos-encoder0Pos));
Serial.println(”steps2″);
Serial.println(steps);
//     Serial.println(((encoder[pointerPos]-encoder0Pos));
}

}
*/
if (millis() - lastChange >= delayMillis*0.8) {
//  if (millis() - lastChange >= 1000) {
// save the reading
encoder[pointerPos]=encoder0Pos;
//  Serial.println(”writingingto”);
// Serial.println(lastEncoder0Pos);
//prog_uchar encoder[pointerPos]=lastEncoder0Pos;
}
}

if (pointerPos == 106){
cycleCount+=1;
pointerPos=0;
if (cycleCount==3){
myStepper2.step(3);
}
Serial.println(”cycleCount”);
}

/*
for (int i=0; i<pointerPos; i++){
encoder[i]=displayRead;
Serial.println(displayRead);
if (displayRead>1 && i==pointerPos){
if (displayRead != encoder0Pos)
myStepper.step(1);
}
}
*/

/*
for( int i=0; i<pointerPos; i++){
encoder[i]=lastEncoder0Pos;
if (lastEncoder0Pos >0){
if (encoder0Pos != lastEncoder0Pos)
{
myStepper.step(1);
}

}
}

*/
}

void doEncoder(){
if (digitalRead(encoder0PinA) == HIGH) {   // found a low-to-high on channel A
if (digitalRead(encoder0PinB) == LOW) {  // check channel B to see which way
// encoder is turning
encoder0Pos = encoder0Pos - 1;         // CCW
}
else {
encoder0Pos = encoder0Pos + 1;         // CW
}
}
else                                        // found a high-to-low on channel A
{
if (digitalRead(encoder0PinB) == LOW) {   // check channel B to see which way
// encoder is turning
encoder0Pos = encoder0Pos + 1;          // CW
}
else {
encoder0Pos = encoder0Pos - 1;          // CCW
}
}

if(encoder0Pos>64){
encoder0Pos=1;
}
if(encoder0Pos<1){
encoder0Pos=64;
}
// Serial.println (encoder0Pos, DEC);          // debug - remember to comment out
}