Monday, September 9, 2013

Littermaid Litterbox fix w/ Arduino

Our Littermaid automatic litter box decided to die a week or two before a week long vacation- exactly when it needs it to work. The motor appeared to be fine- just when plugged in, it would try to return to home position, reach it, and the motor would continue to grind away until the electronics timed out. Then, no more activity. I opened it up and pulled the circuit board out. I hoping to find an obvious problem- burned components or other clues to what failed. Nothing was obvious. I also tested both limit switches, and both seemed to be fine. The motor also easily turned when it was fed 12V DC. Instead of troubleshooting each component, I decided to completely replace the stock electronics with an Arduino and a motor driver shield.

After examining the dissembled litter box, I found a pretty simple machine:

  • 12v DC Gear motor for driving the rake
  • Limit switches for home and maximum travel
  • IR LED / Phototransistor to detect the cat
I wanted this to be as inexpensive and easy as possible of a project, so I chose to re-use all of the stock sensors and motor.

Since an Arduino can't supply the required power or voltage to control the motor, a separate motor driver is needed. I chose to use a Seeedstudio motor drive shield as it was available at the local RadioShack store. This shield is also nice because it'll supply power to the Arduino it is attached to. One big negative, though, is that all of the I/Os are all proprietary "grove" connectors which RadioShack doesn't sell except in a $50 kit. 
Seeed Studio Motor Shield
I did a bunch of searching on the internet to try and find a local solution, or at least one that didn't require ordering parts from China. (Seeed Studios ships from China, not a domestic warehouse) Since I needed to finish this project relatively quickly, I couldn't wait for some parts to arrive from across the Pacific. Sparkfun does carry a cable / connector assembly that is really close. It fits after some modification with a X-acto knife. 
Sparkfun JST Jumper 4-Wire Assembly

The actual wiring of the project was pretty straightforward- basically hook everything up, make sure the appropriate pull-down resistors were in place, then start writing some code. I first wired everything using a standard breadboard, then once it worked I transitioned the parts to a permanently soldered perfboard.


Fritzing illustration of breadboarded setup


I'm no codewarrior, so I wrote the arduino code as simple as possible, with lots of comments. There is also lots of feedback through the serial window to aid in debugging.

Use this project, details, etc at your own risk! 

Arduino Code:


/*
Littermaid catbox control
uses Seeed studio motor shield
portions of code from Seeed example code
 */

// set up sensor & switch pin locations
int sensorPin = A0;   // select the input pin for the cat presence sensor
int endPin = 3;       // select the input pin for the endstop
int homePin = 4;      // select the input pin for the home endstop

// set up motor pin locations, set by the motor shield used
int pinI1=8;               //define I1 interface
int pinI2=11;              //define I2 interface 
int speedpinA=9;           //enable motor A
int spead =255;            //define the spead of motor

// set up various delays
int sensorloopdelay=500; //delay in ms between loop repetitions when waiting for cat
unsigned long delayaftercat=600000; //delay in ms before cycling catbox after cat is detected, 10 minutes


// set up default sensor values
int sensorValue = 100;  // variable to store the value coming from the sensor. starting at 100 so no cat present
int endValue=1; // endstop status
int homeValue=1; // home stop status
unsigned long MaxTravelTime=30000; //maximum time for rake to travel each direction, assumes jammed if didn't finish in alloted time

void setup() {
  // initialize the various inputs and outputs
  pinMode(endPin, INPUT);
  pinMode(homePin, INPUT);
  pinMode(sensorPin, INPUT);
  pinMode(pinI1, OUTPUT);
  pinMode(pinI2, OUTPUT);
  pinMode(speedpinA, OUTPUT);
  
  //set up serial communications with computer
  Serial.begin(9600);
}



void loop() {
// run catbox cycle
int success=0; // cycle success (1) or failure (0)
int i=0; // loop counter

       Serial.println("cat box cycle start");
       
   while (i < 5)
   { // run cycle maximum of 5 times, stop when cycle is successful
     
     success = cycle(); 
     Serial.println(success);
            
     if (success != 0) // break out of 5 rep loop if cycle did not fail
     {
       Serial.println("successfull cycle");
       i=5; // break out of loop
     }
     else
     {
       Serial.println("unsuccessful cycle");
       i=i+1; //increment i
     }

   } 


// reset sensor value
sensorValue = 100; 

// wait until cat is detected
  Serial.println("waiting for cat");


while (sensorValue > 10) 
{
   // read the value from the sensor
   // if > 10 no cat
   // if < 10 cat is present - loop until cat is present
  sensorValue = analogRead(sensorPin); 
  Serial.println(sensorValue); //print sensor value for troubleshooting
    
  delay(sensorloopdelay);
}

  Serial.println("cat detected");
  
// wait until cat leaves
while (sensorValue < 10) 
{
   // read the value from the sensor
   // if > 10 no cat
   // if < 10 cat is present - loop until cat is present
  sensorValue = analogRead(sensorPin); 
  Serial.println(sensorValue); //print sensor value for troubleshooting
  
  delay(sensorloopdelay);
}

  Serial.println("cat left, waiting for specified period of time");
  
// wait for specified period of time before running catbox cycle

delay(delayaftercat); 
                 
}

int cycle() //returns successful cycle or failure
{
  unsigned long startMove_time=0;
  unsigned long time_elapsed=0;
  int success=0; 
  
  Serial.println("start motor out");
  Serial.println("wait until endstop");
  // wait until endstop is reached
  
  startMove_time = millis(); // find time immediately before move start
  
      backward(); // start motor towards endstop
    Serial.println("moving towards endstop");
  
  while (endValue != 0 & time_elapsed
  {
    time_elapsed= millis()-startMove_time; // calculate time elapsed
    endValue=digitalRead(endPin);

  }
  
  stop_motor();
  
  if (endValue==0)
  {
    Serial.println("endstop reached");
    success=1;
  }
  
  if (time_elapsed >= MaxTravelTime)
  {
    Serial.println("outbound travel timed out");
    success=0;
  }
  
  endValue=1; //reset endstop value

  
  Serial.println("stop motor");
  Serial.println("reverse motor");
  Serial.println("wait until home stop");
  
    startMove_time = millis(); // find time immediately before move start
    time_elapsed=0; //reset time elapsed
    
  forward(); // start motor back towards home
          Serial.println("moving towards home");
  
    while (homeValue != 0 & time_elapsed
  {
        time_elapsed= millis()-startMove_time; // calculate time elapsed
        homeValue=digitalRead(homePin);

  }
  
  stop_motor(); // stop motor

  
    if (homeValue==0)
  {
    Serial.println("home stop reached");
    success=1;
  }
  
  if (time_elapsed >= MaxTravelTime)
  {
    Serial.println("inbound travel timed out");
    success=0;
  }
  
  homeValue=1; //reset home stop value
  
  
  Serial.println("stop motor");
  
  return success; //return value back to main loop
  
  
}

void forward()
{
     analogWrite(speedpinA,spead);//input a simulation value to set the speed
     digitalWrite(pinI2,LOW);//turn DC Motor A move anticlockwise
     digitalWrite(pinI1,HIGH);
}

void backward()//
{
     analogWrite(speedpinA,spead);//input a simulation value to set the speed
     digitalWrite(pinI2,HIGH);//turn DC Motor A move clockwise
     digitalWrite(pinI1,LOW);
}

void stop_motor()//
{
     digitalWrite(speedpinA,LOW);// Unenble the pin, to stop the motor. this should be done to avid damaging the motor. 
     delay(1000);
}



No comments:

Post a Comment