Table of Contents

Dispensador de comida para mascotas

Integrantes: Luis Diego Fernández, B22492 Alejandro Rojas, B36049

Descripción del proyecto

Crear un dispensador de comida para mascotas. Se diseñará la estructura del dispensador así como su mecánica de dispensado de comida. Se utilizará un microcontrolador Raspberry Pi y una llave de Wi-fi para que funcione mediante una aplicación móvil. En dicha aplicación se podrán controlar todos los parámetros necesarios para que el dispensador sea adecuado para cualquier mascota.

Obejtivos

Objetivo general

Crear un dispensador de comida para mascotas.

Objetivos específicos

Primera parte

  1. Investigar qué tipo de problemas presentan los dispensadores de comida actuales.
  2. Aprender a trabajar con un microcontrolador Raspberry Pi y con un Piface.
  3. Diseñar un modelo virtual del dispensador de comida.
  4. Aprender a utilizar el programa Android Studio para el desarrollo de aplicaciones en esta plataforma.

Segunda parte

  1. Encontrar un método de dispensado efectivo y libre de problemas.
  2. Controlar el sistema mecánico de dispensado de comida por medio del Raspberry Pi.
  3. Desarrollar una aplicación móvil que logre controlar el dispensador.
  4. Conectar y manejar el Raspberry Pi por medio de la aplicación móvil

Problemas de los dispensadores

Se encontraron algunas críticas a los dispensadores de comida que hay en el mercado, específicamente los detectamos por medio del sistema de comentarios y críticas de Amazon. Entre los principales problemas encontramos:

Trabajo con el Raspberry Pi y Piface

Se descargó el sistema operativo Raspbian, con el cual funcionan los microcontroladores Raspberry Pi. Raspbian es un sistema operativo libre que se basa en Debian, optimizando sus usos para el Hardware del Raspberry Pi. Se instaló Raspbian en una tarjeta SD de 8gb de memoria.

Luego se instalaron las aplicaciones necesarias para poder hacer uso de Piface por medio de la siguiente guía:

http://www.piface.org.uk/guides/Install_PiFace_Software/Enabling_SPI/

Al término de la guía mostrada anteriormente ya se puede probar el Piface por medio de un emulador y también con programas sencillos para familiarizarse con su forma de ser programado.

La importancia del Piface es que este posee 2 relays, estos sirven como switch, (se activan gracias a un campo magnético) para poder utilizar fuentes de poder externas. En este caso se utilizó una fuente de 12 V en CD y está maneja un motor. Se armó un circuito como el de la siguiente imagen: {{ :ie0117_proyectos_i_2015:proyecto_1:piface-relay-connection.png?300 |

Trabajo con el Andorid Studio

Se descargó el programa y se corrieron algunos progamas de prueba para aprender a utilizarlo. De esta manera se creó el primer diseño de la aplicación que se utilizará, esta se hizo con el siguiente código:

   import android.app.TimePickerDialog;
   import android.support.v7.app.ActionBarActivity;
   import android.os.Bundle;
   import android.view.Menu;
   import android.view.MenuItem;
   import android.view.View;
   import android.widget.Spinner;
   import android.widget.EditText;
   import android.widget.TextView;
   import android.widget.ArrayAdapter;
   import android.widget.AdapterView;
   public class dispensador extends ActionBarActivity {
      private EditText Valor1,Valor2;
      private TextView Resultado;
      private Spinner cmbOpciones;
      private String Valores;
      private int select;
     @Override
     protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dispensador);
        final String[] datos =
           new String[] {"1/2 Taza","1 Taza","1 y 1/2 Tazas","2 Tazas","2 y 1/2 Tazas"};
        ArrayAdapter <String> adaptador =
           new ArrayAdapter<String>(this,
              android.R.layout.simple_spinner_item, datos);
        cmbOpciones= (Spinner)findViewById(R.id.spinner);
        adaptador.setDropDownViewResource(
           android.R.layout.simple_spinner_dropdown_item);
        cmbOpciones.setAdapter(adaptador);
        cmbOpciones.setOnItemSelectedListener(
           new AdapterView.OnItemSelectedListener() {
              public void onItemSelected(AdapterView<?> parent,
                 android.view.View v, int position, long id) {
                    Valores = datos[position];
                       if (Valores == "1/2 Taza") {
                          select = 1;
                       }
                       if (Valores == "1 Taza") {
                          select = 2;
                       }
                       if (Valores == "1 y 1/2 Tazas") {
                          select = 3;
                       }
                       if (Valores == "2 Tazas") {
                          select = 4;
                       }
                       if (Valores == "2 y 1/2 Tazas") {
                          select = 5;
                       }
                   }
                  public void onNothingSelected(AdapterView<?> parent) {
                  }
              });
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_dispensador, menu);
      return true;
   }
   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();
      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }
  }

Una vez que compilaba y la emulación funcionaba correctamente se procedió a descargar la aplicación:

Diseño del modelo

Se hizo un diseño virtual en 3D y otro en borrador de los posibles dispensadores de comida que se quieren utilizar, ambos son modelos de pared, que dispensan la comida verticalmente y esta cae en un tazón. Aquí están ambos modelos:

PARTE 2

Método de dispensado efectivo y libre de problemas

En un inicio se planteo el método de usar un tornillo sin fin con franjas pequeñas que a la hora de girar dejara caer la comida hacia el plato o hacia donde se quisiera. Aquí se encontró el primer problema del proyecto, nos dimos cuenta que de esta manera sucedían varias cosas:

  1. La comida que tenía un tamaño superior al de las franjas se quedaba dando vueltas y no caía nunca.
  2. La comida muy pequeña pasaba sola por las franjas y caía.
  3. Ciertos tamaños de comida trababan el tornillo, cuando la comida quedaba en una posicion donde se metía en medio de la franja y el borde del dispensador.

Debido a este inconveniente tuvimos que replantearnos un nuevo diseño mecánico para el correcto funcionamiento de dispensado. Entonces investigamos en Internet que soluciones podíamos tener, sin muchas ideas que no dieran problemas como los anteriores. De esta manera y con un poco de suerte, encontramos un contacto en una compañia de alimentos (por asuntos de confidencialidad nos reservamos el nombre de ellos) el cual nos comentó sobre un método que podría servir de mejor forma. Así fue entonces como llegamos a la idea de utilizar de nuevo un tornillo sin fin, esta vez con franjas mucho más grandes y espaciadas entre sí. Debajo del tornillo se pone un “piso” en el cual cae alimento y el tornillo lo que hace es trasladarlo hacia un lado, donde hay un hueco y de esta manera la comida cae hacia el plato. Esto se puede observar en la siguiente fotografía:

Controlar el sistema mecánico de dispensado de comida por medio del Raspberry Pi

Ahora con el diseño de la mecánica de dispensado listo se acudió a un taller de mecánica de precisión, a ellos se les explicó la idea del proyecto, se les comentó lo que se quería y ellos se encargaron de montar el dispensador. De esta manera, con el dispensador listo, se procedió a pegarle el motor que se había comprado anteriormente. Siguiente a esto, con el dispensador montado junto al motor, llegó la hora de comprobar que el conjunto sirviera. Por lo tanto se armó el circuito correspondiente con el Raspberry Pi + Piface + fuente de voltaje DC. Con todo listo, se procedió a correr el siguiente script de Python, el cual activa el relay 0 por una cantidad variable de tiempo:

   #!-usr-bin-python
   import time
   import pifacedigitalio as p
   p.init()
   p.digital_write(0,1)
   time.sleep(10)
   
   p.digital_write(0.0)

En efecto todo salió como se esperaba. De esta manera y de modo demostrativo, se tiene el siguiente video donde se observa el dispositivo en funcionamiento: https://www.youtube.com/watch?v=Yic9f-db-54&feature=youtu.be

Desarrollar una aplicación móvil que logre controlar el dispensador

Para esta parte del proyecto se siguió trabajando con el Android Studio, logrando que la aplicación generara un entero al escoger la cantidad de tazas que se deseen dispensar, esto para que ese dato sea recibido por el servidor el cuál activará el programa del raspberry pi que mueve el motor para servir el alimento.

El código de la aplicación es el siguiente:

   package com.example.alejandro.dispensador;
   import android.support.v7.app.ActionBarActivity;
   import android.os.Bundle;
   import android.view.Menu;
   import android.view.MenuItem;
   import org.apache.http.HttpResponse;
   import org.apache.http.NameValuePair;
   import org.apache.http.client.HttpClient;
   import org.apache.http.client.entity.UrlEncodedFormEntity;
   import org.apache.http.client.methods.HttpPost;
   import org.apache.http.impl.client.DefaultHttpClient;
   import org.apache.http.message.BasicNameValuePair;
   import android.os.AsyncTask;
   import android.view.View;
   import android.widget.Spinner;
   import android.widget.EditText;
   import android.widget.TextView;
   import android.widget.ArrayAdapter;
   import android.widget.AdapterView;
   import android.widget.Toast;
public class dispensador extends ActionBarActivity {
   private Spinner cmbOpciones;
   private String Valores;
   private int select;
   private TextView Resultado;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_dispensador);
      Resultado=(TextView)findViewById(R.id.textView_Resultado);
      final String[] datos =
              new String[] {"1/2 Taza","1 Taza","1 y 1/2 Tazas","2 Tazas","2 y 1/2 Tazas"};
             ArrayAdapter <String> adaptador =
              new ArrayAdapter<String>(this,
                      android.R.layout.simple_spinner_item, datos);
      cmbOpciones= (Spinner)findViewById(R.id.spinner);
      adaptador.setDropDownViewResource(
              android.R.layout.simple_spinner_dropdown_item);
      cmbOpciones.setAdapter(adaptador);
      cmbOpciones.setOnItemSelectedListener(
              new AdapterView.OnItemSelectedListener() {
                  public void onItemSelected(AdapterView<?> parent,
                                             android.view.View v, int position, long id) {
                      Valores = datos[position];
                      if (Valores == "1/2 Taza") {
                          select = 1;
                      }
                      if (Valores == "1 Taza") {
                          select = 2;
                      }
                      if (Valores == "1 y 1/2 Tazas") {
                          select = 3;
                      }
                      if (Valores == "2 Tazas") {
                          select = 4;
                      }
                      if (Valores == "2 y 1/2 Tazas") {
                          select = 5;
                      }
                  }
                  public void onNothingSelected(AdapterView<?> parent) {
                  }
  });
  }
  public void Operaciones(View view){
      int operacion = 0;
      switch (select){
          case 1:
              operacion=  1;
              break;
          case 2:
              operacion=  2;
              break;
          case 3:
              operacion=  3;
              break;
          case 4:
              operacion=  4;
              break;
          case 5:
              operacion=  5;
              break;
      }
      String resultado = String.valueOf(operacion);
      Resultado.setText(resultado);
  }
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
      getMenuInflater().inflate(R.menu.menu_dispensador, menu);
      return true;
  }
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.
      int id = item.getItemId();
      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
          return true;
      }
      return super.onOptionsItemSelected(item);
  }}

El código del Layout(Parte gráfica) es el siguiente:

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android

  xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".dispensador">
  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Dispensador de Comida para Mascotas"
      android:id="@+id/textView"
      android:layout_alignParentTop="true"
      android:layout_centerHorizontal="true"
      android:shadowColor="#ff44ff24"
      android:textColor="#ff2d3cff" />
  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Ingrese la Cantidad de Tazas de Comida"
      android:id="@+id/textView2"
      android:layout_below="@+id/textView"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_marginTop="35dp" />
  <Spinner
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:id="@+id/spinner"
      android:layout_below="@+id/textView2"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true"
      android:layout_marginTop="35dp" />
  <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Dispensar"
      android:id="@+id/button"
      android:background="#ff408fae"
      android:elegantTextHeight="false"
      android:layout_alignParentBottom="true"
      android:layout_centerHorizontal="true"
      android:layout_marginBottom="125dp"
      android:onClick="Operaciones" />
  <TableRow
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_alignTop="@+id/spinner"
      android:layout_alignParentLeft="true"
      android:layout_alignParentStart="true">
      <TextView
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="Resultado"
          android:id="@+id/textView_Resultado"
          android:layout_gravity="bottom" />
  </TableRow> </RelativeLayout>

Así se ve la aplicacion corriendo en dispositivos móviles

Raspberry Pi como servidor

Con el sistema mecánico listo, con el Raspberry Pi + Piface controlándolo y con la aplicación móvil diseñada se debe proceder a crear un modo de interacción para todo el conjunto.

Se configuró el Raspberry Pi para poder ser utilizado como servidor. En este caso lo más común que se encontró fue utilizarlo como servidor Apache. Para hacer esto se siguió la guía de la página oficial de Apache http://httpd.apache.org/ y se procedío a descargar la versión más nueva, luego se siguió la guía de compilación e instalación http://httpd.apache.org/docs/2.2/install.html. Al hacer esto surgieron un par de problemas a la hora de instalar y configurar los APR (Apache Portable Runtime Project), sin embargo, en la página de instalación sale como solucionarlos, el otro problema fue instalando el PCRE, este se resolvió con la siguiente guía http://www.linuxfromscratch.org/blfs/view/svn/general/pcre.html. Con todo esto se logró hacer que el Raspberry Pi funcionara como un servidor, este servidor quedó en /usr/local/apache2 y se observa de la siguiente manera:

Una vez hecho esto se quiere correr el programa que activa el dispensador de comida por medio del servidor. El servidor puede leer programas html o .cgi. Como nuestro programa está escrito en Python se tienen que cambiar algunos archivos propios del servidor así como el programa de Python. Lo primero, en el archivo /usr/local/apache2/conf/httpd.conf ,del servidor se descomenta la siguiente línea:

   LoadModule cgid_module modules/mod_cgid.so 

Y se agregan las siguientes líneas:

   Options +ExecCGI
   AddHandler cgi-script .cgi
   AddHandler cgi-script .py

que especifican que los archivos .py sean tratados como archivos .cgi, por lo tanto el servidor no enviará un error a la hora de tratar de correrlos.

Luego en el programa de Python hay que agregar 2 líneas al inicio asociadas al cgi:

   import cgitb
   cgitb.enable()

Con todo esto realizado, el servidor podrá correr cualquier script de Python tratandolo como un archivo cgi. Cabe mencionar que dentro del directorio /usr/local/apache2 exite un sub-directorio llamado “cgi-bin”, en este es donde se guardan los programas .cgi que se quisieran ejecutar. Así para correr el programa que pone el dispensador de comida a funcionar habría que accesar el URL www.example/cgi-bin/python_script.cgi (url con fines demostrativos).

Citas bibliográficas