Gruppe:

Jonas Lund – Jolun18@student.sdu.dk
Patrick Nielsen – Panie18@student.sdu.dk
Mads Emil Falkenstrøm – Mafal17@student.sdu.dk


Indledning

Vores problemstilling henvender sig til problematikken omkring automatisering af lys og temperaturregulering af et rum. Når morgen undervisningen begynder kl 8, er det ikke altid man lige får rullet gardinerne fra og lader morgensolen komme ind. Et velkendt scenarie de fleste nok kender til. Dette kan føre til mørke rum, og en forøget elregning da man nu er nødt til at tænde lyset i stedet. Det er måske også nødvendigt at tænde en radiator da solen ikke kan varme rummet op på samme måde som hvis gardinerne var trukket fra.
Det modsatte scenarie kan også gøre sig gældende. Forestil dig at du er midt i en god undervisning, og solen pludselig rammer din skærm så du ikke kan se hvad din underviser har gang i. Men du har heller ikke noget trådløst headset. Hvad gør du? Introducing: 

Light Suppressor 6969.

Et smart automatiseret system der selv åbner og lukker gardinet når temperaturen bliver for høj eller lav. Den medfølgende fjernbetjening sørger for at brugeren selv kan rulle gardinet fra eller til hvis man er uenig med robottens beslutning. Derudover medfølger der også en lydsensor, der gør det muligt at aktivere systemet ved at klappe 2 gange i træk.

Video og billeder

Video demo af klappe funktionen
Video demo af fjernbetjening
Billede af robotten

Opbygning af hardware – fra Fritzing

Følgende komponenter blev brugt i forhold til opsætningen af systemet:

ComponentQuantity
Arduino Uno1x
X113647(ULN2003) Stepper Driver Board1x
Stepper Motor (28BYJ-48)1x
KY-038 Sound Sensor Module1x
KY-022 Infrared Receiver Module1x
Thermistor1x
10k Ω 2x
Green LED1x
Red LED1x
Pushbutton1x

Valgte løsninger

Til systemet er et væld af løsninger blevet implementeret for at sikre god diversitet så alle brugere kan finde den løsning der passer bedst for dem. Der er blandt andet tilført en lydsensor til at opfange når der klappes, for at rulle gardinet til at fra. Yderligere er der tilføjet en knap for mere fysisk anvendelse, og der er også tilføjet en fjernbetjening så man ikke behøver at rejse sig for at trykke på knappen på robotten.
For at robotten automatisk skal kunne rulle gardinerne til eller fra er der tilføjet en termistor for at måle temperaturen. Bliver der for varmt i rummet rulles gardinerne automatisk for, og fra hvis der er for koldt i rummet.
Der er anvendt to LED indikatorer for at vise robottens tilstande. Rød for at indikere at robotten er i mute tilstand, og grøn for at vise at robotten modtager et signal.
Der anvendes en stepper motor og h-bro som gør brug af en darlington motor driver. Dette gøres for at motoren kan dreje både med- og mod uret. Denne funktionalitet gør at gardinet både kan rulles for, men også fra.

Opbygning af program

Flow- og tilstandsdiagrammer

tilstande: PAUSED, CLOSED, OPEN

Funktioner

STEPS

Der er kun 32 trin (11,25 grader) pr. Omdrejning, og indeni er der et reduktionssæt på 1/64. (Faktisk er dens 1 / 64,128, men for de fleste formål er 1/16 en tilstrækkelig tilnærmelse) Hvad dette betyder er, at der virkelig er 32 * 64,128 trin pr. Omdrejning = 2052 trin. [1]

close_curtain

Når vi får stepper motoren til at dreje, går vi det et trin ad gangen og tjekker løbende om man via infrarød fjernbetjeningen har sendt en power off kommando, som vil tvinge robotten i en PAUSE tilstand, der går at vi bryder ud af while loopet, der får motoren til at dreje, når vi er færdige deaktiver vi motoren for at spare på strøm og varme.

get_temperature_in_celcius

Fra spændingsdelerkredsløbs formlen får vi givet at:

Vout= (Vin * Rt) / (R + Rt)

Så vil værdien af Rt være givet på formlen:

Rt = R (Vin/Vout) – 1

Her vil Rt være modstanden af ​​termistor og R vil være 10k ohm modstand.

Denne ligning bruges til beregning af termistorresistens ud fra den målte værdi af udgangsspændingen Vo. Vi kan få værdien af ​​Voltage Vout fra ADC-værdien ved pin A0 i Arduino som vist i Arduino-koden angivet ovenover.

Beregning af temperatur fra termistormodstanden. Matematisk kan termistormodstanden kun beregnes ved hjælp af Stein-Hart-ligningen:

T = 1 / (A + Bln(Rt) + Cln (Rt)3 )

Hvor, A, B og C er konstanterne og Rt er termistormodstanden og ln repræsenterer log.

Den konstante værdi for den anvendte termistor i projektet er A = 1.009249522 × 10−3, B = 2.378405444 × 10−4, C = 2.019202697 × 10−7. Disse konstante værdier kan opnås fra regnemaskinen her ved at indtaste de tre modstandsværdier for termistor ved tre forskellige temperaturer. Du kan enten få disse konstante værdier direkte fra databladet til Thermistor, eller du kan få tre modstandsværdier ved forskellige temperaturer og få konstantværdierne ved hjælp af den givne lommeregner.

Så til beregning af temperaturen har vi kun brug for værdien af termistormodstand. Efter at have fået værdien af Rt fra ovenstående beregning anbringes værdierne i Stein-hart ligningen, og vi får værdien af temperaturen i enheden kelvin. Da der er mindre ændringer i udgangsspændingen, forårsager temperaturændring. [2]

check if sound claps

I vores algoritme for at tjekke om vi har klappet 2 gange for at aktivere gardinet, tjekker vi først om der i øjeblikket er en lyd, for at sikre os at afvise flere lyde i en enkelt loop cyklus tjekker vi på om nuværende støj tid er over sidste støj tid og lægger en grænse på, samt tjekker vi om der var stille før nuværende støj detektion. Derefter bliver der tjekket om det aktuelle klap er mindre end 0.8 sekunder efter det som vi antager for at være det første klap. Til sidst for at undgå et tredje klap som en del af mønsteret.

Prioriteringer

Systemet starter så snart der enten trykkes på fjernbetjeningen, den fysiske knap på maskinen eller den registrerer en klappen, såfremt den ikke er muted. Hvis fjernbetjeningen anvendes kan der, som det ses i flowdiagrammet, anvendes flere knapper for at styre åbning, og lukning af gardiner, samt sætte robotten i pause state. Det er også muligt at “mute” lyd og temperatur.
Den fysiske knap anvendes også til styring af gardinerne, og hvis benyttet tjekkes state først, og derefter åbnes, eller lukkes gardinerne alt efter staten.
Det er også muligt at anvende en klappe mekanisme for at styre gardinet. Hvis robotten ikke er muted, vil den registrere en klappen med hænderne og følger herefter samme mønster som nævnt før. Hvis en klappen ikke bliver registreret vil systemet selv åbne og lukke gardinerne alt efter temperaturen i rummet.

Det er værd at bemærke at fjernbetjeningen vægtes højere end de to andre funktioner, hvor den fysiske knap har en højere prioritet end hvis robotten ikke er muted. Den automatiske løsning vil altså altid vige for brugen af den fysiske knap, som igen må vige for brugen af fjernbetjeningen.

Konklusion

Light Suppressor 6969 leverer en multifunktions indeklima justerings- og optimerings løsning, komplet med automatiseret åbning og lukning af vinduer, en knap så muligheden for selv at styre om de skal være åbne eller lukkede, en lydsensor der gør det muligt at klappe hænderne sammen for at få den til at åbne og lukke, samt en fjernbetjening for nemt at åbne og lukke gardinerne. Vi mener at vores problemstilling er løst med en gennemtænkt løsning.  

Perspektivering

En yderligere udvidelse til systemet ville være tilføjelsen af muligheden for automatisk at åbne og lukke vinduet til at fremme indeklimaet og temperaturregulering.
Det ville yderligere være en opgradering at anvende en stærkere motor for nemmere at kunne dreje gardinet rundt. Diverse sensorer kunne også ændres til analog for at optimere lys- og temperatur sensitiviteten, samt have muligheden for at kunne indstille sensitiviteten via fjernbetjeningen og muligvis tilføje et LCD-display til at give et overblik over nuværende temperatur og hvad ens sensitivitet er sat til. Ved tests kørsel af robotten, fandt vi frem til at robotten vejede for lidt i forhold til den kraft den skulle bruge til at kunne rotere gardinet, så fremadrettet vil en montering på væggen eller tilføje vægt til robotten kunne afhjælpe dette problem.
Light Supressor 6969 har 2 LED’er dog uden nogen resistor. Dette kan være med til at begrænse deres levetid, og bør laves om i det endelige design.

Kode

#include <IRremote.h>
#include <Stepper.h>
#define STEPS 2052 // the number of steps in one revolution of your motor (28BYJ-48)
// general setup
const int delayTime = 500;
const int buttonPin = 6;
int buttonState = 0;    
// sound setup
const int soundSensor = 7;
const int ledPin = 5;
const int mutedLedPin = 4;
boolean val = 0;
bool muted = false;
int lastSoundValue;
int soundValue;
long lastNoiseTime = 0;
long currentNoiseTime = 0;
long lastLightChange = 0;
// motor setup 
int numberOfRotations = 4.5;
//const int stepsPerRevolution = 2048; 
int motorPins[] = {8, 9, 10, 11};
Stepper stepper(STEPS, 8, 10, 9, 11);
// remote setup
int IR_RECEIVE_PIN = 12;
// thermistor
int ThermistorPin = 0;
int Vo;
float R1 = 10000.0;
float logRt, T, Tc;
float A = 1.009249522e-03, B = 2.378405444e-04, C = 2.019202697e-07;
// states
enum RobotStates { PAUSED, CLOSED, OPEN };
RobotStates robotState = OPEN;
void setup() {
  Serial.begin(9600);
  stepper.setSpeed(10);
  pinMode(soundSensor, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(mutedLedPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK, USE_DEFAULT_FEEDBACK_LED_PIN);
}
void disable_motor() {
  for(int num=0;num<4;num++) digitalWrite(motorPins[num],LOW);
}
void check_if_paused_IR_command() {
  if (IrReceiver.decode()) {
     IrReceiver.printIRResultShort(&Serial);
     IrReceiver.resume();
     if (IrReceiver.decodedIRData.command == 0x45) {
        // power off - disable/enable
        robotState = PAUSED;
        Serial.println("Robot PAUSED");
     }
  }
}
void close_curtains() {
  Serial.println("Closing Blinds");
  int ran_steps = 0;
  while (robotState != PAUSED && ran_steps < STEPS*numberOfRotations) {
    check_if_paused_IR_command();
    stepper.step(1);
    ran_steps++;
  }
  robotState = CLOSED;
  disable_motor(); // always desable stepper motors after use to reduce power consumption and heating
}
void open_curtains() {
  Serial.println("Opening Blinds");
  int ran_steps = 0;
  while (robotState != PAUSED && ran_steps > -STEPS*numberOfRotations) {
    check_if_paused_IR_command();
    stepper.step(-1);
    ran_steps--;
  }
  robotState = OPEN;
  disable_motor(); // always desable stepper motors after use to reduce power consumption and heating
}
void control_curtain() {
  if (robotState == CLOSED) {
    open_curtains();
  } else {
    close_curtains();
  }
}
float get_temperature_in_celcius(int Vo) {
  logRt = log(R1*((1024.0/Vo-1)));
  T = (1.0 / (A + B*logRt + C*logRt*logRt*logRt));  // We get the temperature value in Kelvin from this Stein-Hart equation
  Tc = T - 273.15;  // Convert Kelvin to Celsius
  return Tc;
}
void loop() {
  if (IrReceiver.decode()) {
     IrReceiver.printIRResultShort(&Serial);
     IrReceiver.resume();
     // vol up 0x46
     // vol down 0x15
     // power off 0x45
     // play/pause 0x40
     // channel up 0x9
     // channel down 0x7
     if (IrReceiver.decodedIRData.command == 0x9 || IrReceiver.decodedIRData.command == 0x46) {
        // channel up & vol up - curtains up
        digitalWrite(ledPin, HIGH);
        Serial.println("Robot CLOSE");
        close_curtains();
     }
     if (IrReceiver.decodedIRData.command == 0x7 || IrReceiver.decodedIRData.command == 0x15) {
        // channel down & vol down - curtains down
        digitalWrite(ledPin, HIGH);
        Serial.println("Robot OPEN");
        open_curtains();
     }
     if (IrReceiver.decodedIRData.command == 0x45) {
        // power off - disable/enable
        digitalWrite(ledPin, HIGH);
        robotState = PAUSED;
        disable_motor(); // always desable stepper motors after use to reduce power consumption and heating
        Serial.println("Robot PAUSED");
     }
     if (IrReceiver.decodedIRData.command == 0x40) {
        // play/pause - mute/unmute
        digitalWrite(ledPin, HIGH);
        muted = !muted;
        Serial.print("muted: ");
        Serial.println(muted);
        digitalWrite(mutedLedPin, muted);
     }
  }
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
    control_curtain();
  }
  if (!muted) {
      soundValue = digitalRead(soundSensor);
      //Serial.println(soundValue);
      currentNoiseTime = millis();
      if (soundValue == HIGH) { // if there is currently a noise
        if (
          (currentNoiseTime > lastNoiseTime + 200) && // to debounce a sound occurring in more than a loop cycle as a single noise
          (lastSoundValue == 0) &&  // if it was silent before
          (currentNoiseTime < lastNoiseTime + 800) && // if current clap is less than 0.8 seconds after the first clap
          (currentNoiseTime > lastLightChange + 1000) // to avoid taking a third clap as part of a pattern
        ) {
          digitalWrite(ledPin, HIGH);
          lastLightChange = currentNoiseTime;
          control_curtain();
         }
         lastNoiseTime = currentNoiseTime;
      }
  }
  if (!muted) {
    float temperature = get_temperature_in_celcius(analogRead(ThermistorPin));
    if (temperature > 22 && robotState != CLOSED) {
      close_curtains();  
    }
    if (temperature < 20 && robotState != OPEN) {
      open_curtains();
    }
  }
  
  digitalWrite(ledPin, LOW);
  lastSoundValue = soundValue;
} 

Kilder

Leave a Reply