Inspiration -

This project was inspired by being in class all day (the engineering life), unable to take care of a pet and how we could fix that. Most of us out there have wanted a pet fish or have had one, but were always scared you wouldn’t be around to feed it and end up killing it. Many of us who do have fish and go through all the trouble of taking care of it have many difficulties and time conflicts. Going on vacation, weekend trips, daily commute, or going to engineering class on the other side of campus are just hassles that sometimes you wish you could just feed your fish from wherever you were.

What it does -

This product allows you to intimately feed your fish wirelessly in case you forgot to or do not have enough time at home to feed it and want to use the commute to work to feed it or are on vacation.

How it works -

The product is split into three parts that contribute to a total of but not limited to 3 functions/features. The code for all these functions can be found below. The first part is the controller.

The Controller The controller is comprised of an arduino microcontroller, a 3 axis accelerometer, a master bluetooth transmitter and a push button. The controller is programmed so that when you want to feed your fish, you have to push the button and shake the controller at the same time.

But what makes this product so different from an ordinary robotic, monotonous fish feeder? Well, first ask yourselves, why do you have a fish, a pet in the first place? You want a friend to take care of and love. Well feeding is one of the most loving actions you could do.

We use hard-coded threshold values for deviations from the baseline acceleration values from when you turn it on to check whether or not you are shaking the controller while the button is pressed. Once the arduino recognizes that you are indeed pressing the button and shaking the controller, it sends a signal over Bluetooth to the receiver on the fish feeder. The next part is the receiver which is connected to the actual fish feeder itself.

The Receiver/Fish Feeder The receiver comprises of an arduino, ethernet shield, and bluetooth receiver. The receiver is programmed to continually wait for a signal from the transmitter and when it receives the signal, it sends another signal through wire to the fish feeder.

The actual fish feeder itself is composed of a continuous rotation servo motor, 3D printed water wheel, hopper, and frame. Once the receiver receivers and sends the signal to the feeder, the motor turns for half a second, turning the wheel and dispensing a certain amount of fish food. The hopper is designed to make certain that all fish food put into it, ends up in the wheel and gets dispensed. The last part is thingspeak, the online interface.

Thingspeak Thingspeak is used as when the receiver receives the signal, the arduino fetches the current epoch time through the internet and uploads it to Thingspeak.com using the ethernet cable and shield. On Thingspeak, using MATLAB visualization and analysis, statistics about your feeding habits and times are displayed. You check how consistently you feed your fish and you can check how many times you have fed your fish including the last time you have to make sure you feed it every day.

There are many more adaptations available with more and more resources.

Note for TAs: The 2 minute promotional video can be found here: https://www.youtube.com/watch?v=_lGi-aSByAE and if you cannot see the technical it can be found here: https://www.youtube.com/watch?v=V-xSGFIBDLY

Receiver Code

#include <SPI.h>
#include <Servo.h>
#include <Ethernet.h>
#include <SoftwareSerial.h>
#include <SoftReset.h>

unsigned int localPort = 8888; //local port to listen UDP packets
char timeServer[] = "time.nist.gov"; 
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
EthernetUDP Udp;

//RX TX bluetooth module digital pins
SoftwareSerial  BTSerial(2, 3);

// Local Network Settings
// Must be unique on local network
byte mac[] = {0x90, 0xA2, 0xDA, 0x0D, 0xD2, 0xC6};  
// you must change this
IPAddress ip(192, 168, 1, 109); 

// ThingSpeak Settings
char thingSpeakAddress[] = "api.thingspeak.com";
// you must change this
String writeAPIKey = "3CDPP6MET80GNVNZ"; 
//Delay time to next possible shake
int updateThingSpeakInterval = 2000;

// Initialize Arduino Ethernet Client
EthernetClient client;

//Initialize the servo motor
Servo motor;

void setup() {
  BTSerial.begin(9600); //begin bluetooth communication
  Serial.begin(9600); //begin serial communication
  // Start Ethernet on Arduino
  client.stop();
  Ethernet.begin(mac, ip);
  motor.attach(8);
  motor.write(92);
  Udp.begin(localPort);
}

void loop() {
  if (BTSerial.available()) {
    //reads single character at a time
    char inChar = (char) BTSerial.read();
    if(inChar == 'H') {
      motor.write(85); //Change this speed to be reasonable 
      delay(500); //Change this delay to be reasonable
      motor.write(92); //Stop motor
      // Update ThingSpeak
      int time = getTime();
      if (time < 5) {
        time = 19 +  time;
      } else {
        time = time - 5;
      }
      updateThingSpeak("field1="+String(time));
      soft_restart();
    }
  }
}

void updateThingSpeak(String tsData) {
  if (client.connect(thingSpeakAddress,80)) {  
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(tsData.length());
    client.print("\n\n");
    client.print(tsData);
    Serial.println("Updated thingspeak: " + tsData);
    delay(1000);
  }
}

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(char* address) {
  Serial.println("sending packet");
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}


int getTime() {
  Serial.println("getting time");
  sendNTPpacket(timeServer); // send an NTP packet to a time server

  // wait to see if a reply is available
  delay(1000);
  if (Udp.parsePacket()) {
    Serial.println("packet parsed");
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

    // the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, extract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    Serial.print("Seconds since Jan 1 1900 = ");
    Serial.println(secsSince1900);

    // now convert NTP time into everyday time:
    Serial.print("Unix time = ");
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    unsigned long epoch = secsSince1900 - seventyYears;
    // print Unix time:
    Serial.println(epoch);

    Serial.println("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT)
    int hour = (epoch  % 86400L) / 3600;
    Serial.print(hour); // print the hour (86400 equals secs per day)
    return hour;
  }
}

Transmitter Code

#include <SoftwareSerial.h>
//RX TX on Bluetooth module, digital pins
SoftwareSerial  BTSerial(2, 3);
//button digital pin
const int button = 13;
//value returned by button
int val = 0;

//Analog read pins for accelerometer
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;

//Baseline values for accelerometer, we only
//care about the absolute value of the change 
//in acceleration
int xbl, ybl, zbl;

//Thresholds for fishfood shake
int threshold[3] = { 80, 40, 40 };

void setup() {
  BTSerial.begin(9600);
  Serial.begin(9600);
  //Defining button pin as input
  pinMode(button, INPUT);
  int xbla[50], ybla[50], zbla[50];
  for(int i = 0; i < 50; i++) {
    xbla[i] = analogRead(xPin);
    ybla[i] = analogRead(yPin);
    zbla[i] = analogRead(zPin);
  }
  xbl = sum(xbla) / 50;
  ybl = sum(ybla) / 50;
  zbl = sum(zbla) / 50;
}

int sum(int array[]) {
  int sum = 0;
  for (int i = 0; i < sizeof(array); i++) {
    sum = sum + array[i];
  }
  return sum;
}

void loop() {
  //read the analog values from the accelerometer
  int xRead = abs(analogRead(xPin) - xbl);
  int yRead = abs(analogRead(yPin) - ybl);
  int zRead = abs(analogRead(zPin) - zbl);

  //read the value from the button, 
  //whether it is pressed or not
  val = digitalRead(button);

  Serial.println(val);

  //Check if button is pressed and the controller is shaked
  if(val == HIGH && (xRead > threshold[0] || 
  yRead > threshold[1] || zRead > threshold[2])) {
    BTSerial.println("H");
  }
  delay(2000);
}

Thingspeak Visualization Matlab Code

% Channel ID to read data from
readChannelID = 71223;
readkey = 'L5WC4RZ6WCM9GK4T';
% Temperature Field ID
TimeID = 1;

[data, time] = thingSpeakRead(readChannelID, 'Fields', TimeID,'ReadKey',readkey,'NumPoints',100);
% disp(data)
NUM = length(data);
% [data2, time] =thingSpeakRead(readChannelID, 'Fields', TimeID,'ReadKey',readkey,'NumPoints',NUM);
histogram(data);
xlabel('Time');
ylabel('Number of Times Fed');
title({['Your Feeding Habits: ','You have fed your fish ',num2str(NUM),' times'];...
['You last fed your fish at around ',num2str(data(end)),':00']});
axis tight
grid on

Built With

Share this project:
×

Updates