Introduction: Reptile Autocare

This instructable was created in fulfillment of the project requirement of the Makecourse at the University of South Florida (www.makecourse.com).

The goal of this project was to create a system to automatically take care of a reptile for up to a week without human intervention. These parts are specifically designed with a chameleon in mind, but could be used or adjusted for other animals/plants.

Step 1: Understanding the 3 Main Functions and 3D Part Designs, Light

CAREFUL: Playing with 120 V is dangerous. Keep the leads to your relat short and put tape on the button of your relay or it will shock you. Keep away from all liquids and properly insulate. Use your head for everyhting else. You are responsible for your safety.

It's not toooo dangerous, but be safe.

Above is an image of a light bulb in a socket. Most reptiles need a light turned on and off daily. So, the first functionality of the procet is turning a 120V light on and off automatically. The user will be able to adjust the times ON and OFF occurs.

Step 2: Animal Feeder

Above is an image of an automatic animal feeder. Every reptile eats! In this case the project was designed for a chameleon which typically eat 2ish worms or crickets a day. The feeder contains 7 chambers. One chamber would open a day to automatically feed for up to a week. The lid has rails super glued to them and is moved by a gear that is connected to the stepper motor you see here via a makeshift tape and glue connection (just redneck it).

All parts described here were 3D designed and printed. Rails and gears can easily be found already designed online (mcmaster.com). You can see in the image that I have split my feeder. If your feeder is too long for the printer you may want to consider spliting it and then connecting the two have.

Step 3: Spray System

Above is an image of what is used to activate a spray bottle to mosturize the reptile's environment. This is expecially important for chameleons and should be done about every 2 hours. The frequency and number of sprays are adjustable by the user.

The spray system is comprised of the white rectangle used for fixing a spray bottle and a high torque 360 degree servo motor. The servo motor drives the cam to press the trigger on the spray bottle. This works pretty well when you set a spray bottle with a long trigger inside. To be honest the servo does not hold it's position like a normal servo because it is a 360 degree servo because coding is even different. I did not know that starting this project and I was required to 3D design and print 2 seperate mechanical parts that move freely of each other. Although, the cam and and rectangle were 3D printed and designed by myself. Besides this the system works well right now, although it sounds as if the not so cheap servo might be starting to fail mechanically after some use. If you want to recreate this project honestly just buy something like a mister which you could connect where this device is and still set the frequency of opperation.

Step 4: Circuit

The image above is the complete circuit for the Reptile Autocare system. There are comments in the image to assist with understanding each component. Some components were not found in the software used to create this. So, some of the components are not the exact compnent you would use, but are correctedd by the comments.

Let's begin with the arduino because that is where everything branches from. Pins 4-11 control the 8 buttons on the breadboard. The top four buttons will control the ON/OFF settings for the light. The user will be able to toggle up and down. The bottom four buttons allow you to reset the feeding time, spray frequency, and spray amount/duration. Pin 2 controls the servo. Pin 12 controls the light. Above this are the SCL and SDA pins used to control the Real Time Clock (RTC) and the I2C LCD screen. Pins A0-A3 control the stepper motor. Everything is powered from the ground and 5V pin. The stepper requires the ULN2003A driver to operate. The light requires a relay and outlet plug to 120V as shown.

CAREFUL: Playing with 120 V is dangerous. Keep the leads to your relat short and put tape on the button of your relay or it will shock you. Keep away from all liquids and properly insulate. Use your head for everyhting else. You are responsible for your safety.

It's not toooo dangerous, but be safe.

Step 5: The Code

//ALester<p>// Reptile Autocare system</p><p>//------------Including libraries and creating variables-----------------</p><p>#include 
 //Libraries
#include 
#include </p><p>RTC_DS1307 RTC;
LiquidCrystal_I2C lcd(0x27,16,2); ; //Arduino pins to lcd</p><p>const int DOWN_BUTTONon =9;        //Buttons Pins
const int UP_BUTTONon =8;
const int DOWN_BUTTONoff =11;       
const int UP_BUTTONoff =10;
const int Relay =12;             //Relay pin</p><p>//-----Variables for debouncing------//</p><p>boolean lastDownONButton = LOW;
boolean currentDownONButton = LOW;
boolean lastUpONButton = LOW;
boolean currentUpONButton = LOW;
boolean lastDownOFFButton = LOW;
boolean currentDownOFFButton = LOW;
boolean lastUpOFFButton = LOW;
boolean currentUpOFFButton = LOW;</p><p>int SET = 7;
int FREQUENCY = 6;
int NUMBER = 5;
int traytime = 12;
int set_on = 12;        //The default "ON" desired time
int set_off = 12;       //The default "OFF" desired time
int traypin = 4;</p><p>//--------servo-----
#include 
Servo myservo;
int set_freq = 2;
int set_number = 2;
int turns = 0;</p><p>//--------------motor intitilizing--------------
#include </p><p>#define delaytime 20 //delay time in ms to control the stepper motor delaytime.
//Our tests showed that 8 is about the fastest that can yield reliable operation w/o missing steps</p><p>const int stepsPerRevolution = 4920;</p><p>int pin1 = A0;
int pin2 = A1;
int pin3 = A2;
int pin4 = A3;</p><p>// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, pin1, pin2, pin3, pin4);</p><p>int stepCount = 0;  // number of steps the motor has taken</p><p>//-------------------void setup--------------------------------------------------------
//setting up the lcd screen and setting input/output pins</p><p>void setup(){</p><p>//-----------------    stepper void setup stepper    --------  feeder  ------------</p><p>    pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
myStepper.setSpeed(30);</p><p>//---------------- servo ----------- spray bottle at input frequency --------
    myservo.attach(2);</p><p>//  -----------  other stuff  ----------
  
lcd.backlight();
  
  pinMode(Relay, OUTPUT);
  
     Wire.begin();
     RTC.begin();
     lcd.begin(16, 2); // Configura lcd numero columnas y filas
     
     lcd.setCursor(0,0);  //Show "TIME" on the LCD
     lcd.print("TIME");
     lcd.setCursor(0,1);
     lcd.print("ON");    //Show "ON" on the lcd
     lcd.setCursor(6,1);
     lcd.print("OFF");  //Show "OFF" on the lcd</p><p>  pinMode(SET, INPUT);
  pinMode(FREQUENCY, INPUT);
  pinMode(NUMBER, INPUT);
  pinMode(traypin, INPUT);</p><p>  RTC.adjust(DateTime(__DATE__, __TIME__)); //sets RTC to time and date of upload</p><p>  
}</p><p>     
   //----Debouncing function for all buttons----//
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}
     </p><p> //------------------     void loop ----------  void loop  -------------  void loop   -----------------------------------</p><p>void loop(){</p><p>int s = 0;
  int f = 0;
  int n = 0;
  int t = 0;
  s = digitalRead(SET);
  f = digitalRead(FREQUENCY);
  n = digitalRead(NUMBER);
  t = digitalRead(traypin);</p><p>  //-----operating and printing button values for frequency, number, and tray time-----//
  if (s == HIGH)
  {
    set_freq = 0;
    set_number = 0;
    traytime = 0;
  }</p><p>  if (f == HIGH && set_freq < 24) {
    if (set_freq == 0) {
      set_freq = 1;
      delay(200);
    }
    if(set_freq <8){
    set_freq = set_freq * 2;
    delay(200);
    }
    if(set_freq == 8){
      set_freq = 12;
      delay(200);
    }
    else{ 
      delay(200);
  }
  }
  
  if (n == HIGH && set_number < 9) {
    set_number++;
    delay(200);
  }
  if (t == HIGH && traytime < 24) {
    traytime++;
    delay(200);
  }</p><p>  //----print---
  lcd.setCursor(14, 0);
  lcd.print(traytime);
  lcd.print(" ");
  lcd.setCursor(13, 1);
  lcd.print(set_freq);
  lcd.print(" ");
  lcd.setCursor(15, 1);
  lcd.print(set_number);</p><p>  
//--------Show current Time On LCD--------//</p><p>DateTime now = RTC.now();        // Clock call
now = RTC.now();</p><p>lcd.setCursor(5,0);                 
if(now.hour() < 10)
{
lcd.print("0");
}
lcd.print(now.hour(), DEC); //Print hour
lcd.print(':');
if(now.minute() < 10)
{
lcd.print("0");
}
lcd.print(now.minute(), DEC); //Print min
lcd.print(':');
if(now.second() < 10)
{
lcd.print("0");
}
lcd.print(now.second(), DEC); //Print sec</p><p>//----Debounce  buttons---//
currentDownONButton = debounce(lastDownONButton, DOWN_BUTTONon);
currentUpONButton = debounce(lastUpONButton, UP_BUTTONon);
currentDownOFFButton = debounce(lastDownOFFButton, DOWN_BUTTONoff);
currentUpOFFButton = debounce(lastUpOFFButton, UP_BUTTONoff);</p><p>//-----Turn down the set "ON"-----//
if (lastDownONButton== LOW && currentDownONButton == HIGH)
{
if(set_on>0){    //"ON" Set point  down never lower than 0
set_on--;        
}
else{
  lcd.setCursor(3,1);
  lcd.print("0");
}
}</p><p>//----Turn up the set "ON"----//
else if (lastUpONButton== LOW && currentUpONButton == HIGH)
{
  if(set_on<23){   //"ON" Set point up never higher than 23
  set_on++;
}
else{
  lcd.setCursor(3,1);
  lcd.print("23");
}
}</p><p>//---Print the set "ON"---//
lcd.setCursor(3,1);
if(set_on < 10){   
  lcd.print("0");
}
lcd.print(set_on);
lastDownONButton = currentDownONButton;
lastUpONButton = currentUpONButton;</p><p>//-----Turn down the set "OFF"-----//
if (lastDownOFFButton== LOW && currentDownOFFButton == HIGH)
{
if(set_off>0){    //"OFF" Set point  down never lower than 0
set_off--;
}
else{
  lcd.setCursor(10,1);
  lcd.print("0");
}
}</p><p>//----Turn up the set "OFF"----//
else if (lastUpOFFButton== LOW && currentUpOFFButton == HIGH)
{
  if(set_off<23){   //"OFF" Set point up never higher than 23
  set_off++;
}
else{
  lcd.setCursor(10,1);
  lcd.print("23");
}
}</p><p>//---Print the set "OFF"---//
lcd.setCursor(10,1);
if(set_off < 10){   
  lcd.print("0");
}
lcd.print(set_off);
lastDownOFFButton = currentDownOFFButton;
lastUpOFFButton = currentUpOFFButton;</p><p>//----Relay Function----//
if(set_on == set_off){
   digitalWrite(Relay, LOW);
}</p><p>if(set_on < set_off){
  
             if(now.hour() >= set_on && now.hour() < set_off ){             //Start
             digitalWrite(Relay, LOW);
             }
             else if(now.hour() >= set_off) {
             digitalWrite(Relay, HIGH);
             }
             else{
             digitalWrite(Relay, HIGH);
             }
}
if (set_on > set_off){</p><p>            if(now.hour() >= set_on && now.hour() <= 23){                  //Start
            digitalWrite(Relay, LOW);  
            }
            else if(now.hour() < set_off){
            digitalWrite(Relay, LOW);
            }
            else if(now.hour() >= set_off && now.hour() < set_on){
            digitalWrite(Relay, HIGH);  
            }
}</p><p>//-------------- feeder  --------- operates when the tray opens for feeding every day -------------------</p><p>  //if(traytime0){
  forward();
  stepCount --;
  }
  delay(3000);
  }</p><p>//---------- spray bottle --------------- sprays at input frequency and duration ----------------
  
  //if here ( if the certain time is reached, run this lines
  //of codes.</p><p>// if (FREQUENCY == 1) {
//    //if(FREQUENCY</p><p>       if ((set_freq == 1 &&  now.hour() == 0  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 1  && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 2 && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 3 && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 4 && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 5  && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 6 && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 7  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 8  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 9  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 10  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 11  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 &&  now.hour() == 12  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 13  && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 14 && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 15 && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 16 && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 17  && now.minute() == 0 && now.second() == 0) || ( set_freq == 1 && now.hour() == 18 && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 19  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 20  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 21  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 22  && now.minute() == 0 && now.second() == 0) || (set_freq == 1 && now.hour() == 23  && now.minute() == 0 && now.second() == 0) ){
       turns = set_number;
        //--------servo-----
        //Use the Servo library. Instead of angles the Servo.write(position) will determine the speed and direction. A value close to 90 will make it stop and higher values will represent one direction, lower values the other direction.
  while(turns > 0){
  myservo.attach(2);
  delay(15);
  myservo.write(240);
  delay(1020);
  myservo.detach();
  delay(50);
  myservo.attach(2);
  delay(15);
  myservo.write(90);
  delay(15);
  myservo.detach();
  delay(15);</p><p>turns = turns - 1;
  
    }
       }</p><p>       if ((set_freq == 2 &&  now.hour() == 0  && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 2  && now.minute() == 0 && now.second() == 0) || ( set_freq == 2 && now.hour() == 4 && now.minute() == 0 && now.second() == 0) || ( set_freq == 2 && now.hour() == 6 && now.minute() == 0 && now.second() == 0) || ( set_freq == 2 && now.hour() == 8 && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 10  && now.minute() == 0 && now.second() == 0) || ( set_freq == 2 && now.hour() == 12 && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 14  && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 16  && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 18  && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 20  && now.minute() == 0 && now.second() == 0) || (set_freq == 2 && now.hour() == 22  && now.minute() == 0 && now.second() == 0)  ){
       turns = set_number;
        //--------servo-----
        //Use the Servo library. Instead of angles the Servo.write(position) will determine the speed and direction. A value close to 90 will make it stop and higher values will represent one direction, lower values the other direction.
  while(turns > 0){
  myservo.attach(2);
  delay(15);
  myservo.write(240);
  delay(1020);
  myservo.detach();
  delay(50);
  myservo.attach(2);
  delay(15);
  myservo.write(90);
  delay(15);
  myservo.detach();
  delay(15);</p><p>turns = turns - 1;
  
    }
       }</p><p>       if ((set_freq == 4 &&  now.hour() == 0  && now.minute() == 0 && now.second() == 0) || (set_freq == 4 && now.hour() == 4  && now.minute() == 0 && now.second() == 0) || ( set_freq == 4 && now.hour() == 8 && now.minute() == 0 && now.second() == 0) || ( set_freq == 4 && now.hour() == 12 && now.minute() == 0 && now.second() == 0) || ( set_freq == 4 && now.hour() == 16 && now.minute() == 0 && now.second() == 0) || (set_freq == 4 && now.hour() == 20  && now.minute() == 0 && now.second() == 0) ){
       turns = set_number;
        //--------servo-----
        //Use the Servo library. Instead of angles the Servo.write(position) will determine the speed and direction. A value close to 90 will make it stop and higher values will represent one direction, lower values the other direction.
  while(turns > 0){
  myservo.attach(2);
  delay(15);
  myservo.write(240);
  delay(1020);
  myservo.detach();
  delay(50);
  myservo.attach(2);
  delay(15);
  myservo.write(90);
  delay(15);
  myservo.detach();
  delay(15);</p><p>turns = turns - 1;
  
    }
       }</p><p>       if ((set_freq == 6 &&  now.hour() == 0  && now.minute() == 0 && now.second() == 0) || (set_freq == 6 && now.hour() == 6  && now.minute() == 0 && now.second() == 0) || ( set_freq == 6 && now.hour() == 12 && now.minute() == 0 && now.second() == 0) || ( set_freq == 6 && now.hour() == 18 && now.minute() == 0 && now.second() == 0) ){
       turns = set_number;
        //--------servo-----
        //Use the Servo library. Instead of angles the Servo.write(position) will determine the speed and direction. A value close to 90 will make it stop and higher values will represent one direction, lower values the other direction.
  while(turns > 0){
  myservo.attach(2);
  delay(15);
  myservo.write(240);
  delay(1020);
  myservo.detach();
  delay(50);
  myservo.attach(2);
  delay(15);
  myservo.write(90);
  delay(15);
  myservo.detach();
  delay(15);</p><p>turns = turns - 1;
  
    }
       }</p><p>       if ((set_freq == 8 &&  now.hour() == 0  && now.minute() == 0 && now.second() == 0) || (set_freq == 8 && now.hour() == 8  && now.minute() == 0 && now.second() == 0) || ( set_freq == 8 && now.hour() == 16 && now.minute() == 0 && now.second() == 0) ){
       turns = set_number;
        //--------servo-----
        //Use the Servo library. Instead of angles the Servo.write(position) will determine the speed and direction. A value close to 90 will make it stop and higher values will represent one direction, lower values the other direction.
  while(turns > 0){
  myservo.attach(2);
  delay(15);
  myservo.write(240);
  delay(1020);
  myservo.detach();
  delay(50);
  myservo.attach(2);
  delay(15);
  myservo.write(90);
  delay(15);
  myservo.detach();
  delay(15);</p><p>turns = turns - 1;
  
    }
       }</p><p>       if ((set_freq == 12 &&  now.hour() == 0  && now.minute() == 0 && now.second() == 0) || (set_freq == 12 && now.hour() == 8  && now.minute() == 0 && now.second() == 0) ){
       turns = set_number;
        //--------servo-----
        //Use the Servo library. Instead of angles the Servo.write(position) will determine the speed and direction. A value close to 90 will make it stop and higher values will represent one direction, lower values the other direction.
  while(turns > 0){
  myservo.attach(2);
  delay(15);
  myservo.write(240);
  delay(1020);
  myservo.detach();
  delay(50);
  myservo.attach(2);
  delay(15);
  myservo.write(90);
  delay(15);
  myservo.detach();
  delay(15);</p><p>turns = turns - 1;
  
    }
       }</p><p>}// The End</p>

Step 6: Code Description

The first part of this code includes libraries for things such as the LCD and RTC. Other things before we start the void setup includes intitilizing variables, constents, and the stepper and so forth.

Next in the void setup we set output pins, the servo pin, and a few other pins.

The void loop is next and is lengthy. We begin operating the 4 buttons for the values of the spray bottle (servo) operation and animal feeder (stepper) operations. A few if statements and a few lines for printing the values on the LCD take care of this.

Then have code for displaying the time. Followed by if statements for operating the 4 buttons for adjusting the ON/OFF values of the light. We print these values and then have if statements to allow the relay to opporate accordingly.

Finally we have code to operate the feeder and the spray bottle. The feeder code is simple, but the spray bottle code is a little much more legnthy. Each if statement for the spray bottle correlates to a frequency option the user has.

This concludes my project.