回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

物联网自动猫粮机 简单

头像 DFSH_Felix 2018.10.11 1885 7

项目背景

       当你忙于工作,中午无法回家;当你回家途中惨遭堵车,无法按时到家;当时需要出差,当你需要约会…...这些情况都会导致家里的宠物处于挨饿或无法按时按量吃饭的状态! 宠物比人类脆弱的多,以上的种种情况都有可能导致宠物患上肠胃疾病!这时候,你就需要一款可以自动或者远程控制的智能猫/狗粮机,来帮你按时按量的投喂家里的小可爱们!并且可以统计小可爱们的吃饭时间,以便在需要的时候向宠物医生反馈,时刻关注家中宠物的健康! 

        那么先看看我们需要准备些什么吧!~

project-image

材料清单

  • 3mm椴木板 X1
  • 4mm椴木板 X2
  • Gravity: UART OBLOQ - IoT物联网模块 X3 链接
  • Romeo V2 多合一Arduino兼容控制器 X4 链接
  • Gravity I2C OLED-2864 显示屏 X5 链接
  • 带编码器金属直流减速电机 (6V 300rpm 3.6Kg.cm) X6 链接
  • 数字触摸开关Touch(Arduino兼容) X7 链接
  • 75*2.3mmPVC水管 X8

步骤1 猫粮机结构件制作

木板激光切割

       首先,我们需要进行猫粮机整体结构的加工,考虑到拼装的便捷性和材料的成本,我们的猫粮机采用木板和螺丝固定的结构。猫粮机的激光切割图纸,我会放在帖子最后的资料中供大家下载,大家也可以在现有的基础上,给猫粮机增加更好看的外观,给家里的“主子”们做一个独一无二的猫粮机。

project-image

PVC水管切割

       木板切割完成后,我们需要制作猫粮机输送猫粮的管道,这个就需要我们之前准备的PVC水管(直径和厚度千万不要买错哦~)。我们需要切割一段178mm长的PVC水管,然后在其中一侧用手锯切出一个35mm长,5mm深的槽,以便于安装我们猫粮机的入口。

project-image

3D打印

       最后,我们还缺一个推动猫粮的绞龙,以及安装在PVC水管两侧防止猫粮从管道中掉落的封盖。3D打印时需要用到的STL文件,我也会在帖子最后的资料中贴上的~绞龙最终打印出来就是下图的效果啦~

project-image

步骤2 猫粮机的拼装

        完成了所有的结构件制作,接下来我们就要进到最繁琐的拼装环节!在进行拼装之前,提醒一下各位!在猫粮机外壳拼装的时候,需要在螺丝和螺母的基础上,添加一个垫片,增加结构的稳定性,也防止了用力过猛拧断木板的情况(即使这样也不要用力太猛!)!正确的安装方式如下~

project-image

      因为制作拼装图纸过于繁琐,我给大家一个安装到一半的图,以便大家理解拼装过程。拼装过程中,如果遇到一些不稳定的结构,各位可以使用热熔胶或者502辅助固定。

project-image

       拼装到还剩最后一块侧面板时,我们将主控以及各种模块放入机器中。

project-image

步骤3 烧录程序

        这一版的猫粮机,具有可以使用OBLOQ控制猫粮机运行模式的功能。向optic2发送数据1,猫粮机持续出粮;发送数据0,猫粮机停止出粮;发送数据2,猫粮机进入自动模式,外接的触摸传感器每隔一段时间(这段时间可以在程序中自行更改)允许猫咪触摸后出粮。烧录完程序后,将最后一块木板装上,猫粮机就制作完成啦!

代码
#include <PID_v1.h>
#include "U8glib.h"
#include <SoftwareSerial.h>
#include "Obloq.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);  // I2C / TWI

static const unsigned char PROGMEM str_kong[] =
{0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x88,0x24,0x10,0x10,0x20,0x08,0x00,0x00,
0x1F,0xF0,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x7F,0xFC,0x00,0x00};/*"空",0*/
static const unsigned char PROGMEM str_bai[] =
{0x01,0x00,0x02,0x00,0x04,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,
0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08};/*"白",1*/
static const unsigned char PROGMEM str_zong[] =
{0x10,0x10,0x08,0x20,0x04,0x40,0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x10,0x10,
0x1F,0xF0,0x10,0x10,0x01,0x00,0x08,0x84,0x48,0x92,0x48,0x12,0x87,0xF0,0x00,0x00};/*"总",2*/
static const unsigned char PROGMEM str_liang[] =
{0x00,0x00,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x10,0x10,0xFF,0xFE,0x00,0x00,0x1F,0xF0,
0x11,0x10,0x1F,0xF0,0x11,0x10,0x1F,0xF0,0x01,0x00,0x1F,0xF0,0x01,0x00,0x7F,0xFC};/*"量",3*/
static const unsigned char PROGMEM str_ci[] =
{0x00,0x80,0x40,0x80,0x20,0x80,0x20,0xFC,0x01,0x04,0x09,0x08,0x0A,0x40,0x14,0x40,
0x10,0x40,0xE0,0xA0,0x20,0xA0,0x21,0x10,0x21,0x10,0x22,0x08,0x24,0x04,0x08,0x02};/*"次",4*/
static const unsigned char PROGMEM str_shu[] =
{0x08,0x20,0x49,0x20,0x2A,0x20,0x08,0x3E,0xFF,0x44,0x2A,0x44,0x49,0x44,0x88,0xA4,
0x10,0x28,0xFE,0x28,0x22,0x10,0x42,0x10,0x64,0x28,0x18,0x28,0x34,0x44,0xC2,0x82};/*"数",5*/
static const unsigned char PROGMEM str_shi[] =
{0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x88,0x84,0x04,0x80,0x04,0x80,0x10,0x80,
0x08,0x80,0x08,0x80,0xFF,0xFE,0x01,0x40,0x02,0x20,0x04,0x10,0x18,0x08,0x60,0x04};/*"实",6*/
static const unsigned char PROGMEM str_m[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00};/*":",0*/
static const unsigned char PROGMEM str_g[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x44,0x44,0x38,0x40,0x3C,0x42,0x42,0x3C};/*"g",0*/
static const unsigned char PROGMEM str_cat[] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xEF,0x8F,0x80,0x00,0x00,
0x00,0x00,0x03,0xE7,0xFF,0x00,0x00,0x00,0x00,0x00,0x03,0xE3,0xFF,0x00,0x00,0x00,
0x00,0x00,0x0F,0xE0,0x0F,0x00,0x00,0x00,0x00,0x00,0x0F,0x38,0x1E,0x00,0x00,0x00,
0x00,0x00,0x0F,0xF8,0x1E,0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x7C,0x00,0x00,0x00,
0x00,0x00,0x07,0xFB,0xFE,0x00,0x00,0x00,0x00,0x00,0x06,0xC3,0xFE,0x00,0x00,0x00,
0x00,0x00,0x07,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x38,0x00,0x00,0x00,
0x00,0x00,0x03,0x80,0x70,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x70,0x00,0x00,0x00,
0x00,0x00,0x03,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x38,0x00,0x00,0x00,
0x00,0x00,0x03,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x0F,0x00,0x00,0x00,
0x00,0x00,0x03,0x00,0x07,0x80,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0xC0,0x00,0x00,
0x00,0x00,0x03,0x80,0x01,0xE0,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0xE0,0x1C,0x00,
0x00,0x00,0x03,0xE0,0x00,0x60,0x3E,0x00,0x00,0x00,0x03,0x60,0x18,0x70,0x73,0x80,
0x00,0x00,0x03,0x70,0x38,0x30,0x79,0x80,0x00,0x00,0x03,0x39,0xB0,0x30,0x79,0xC0,
0x00,0x00,0x03,0xB9,0xF0,0x30,0x19,0xC0,0x00,0x00,0x01,0xBD,0xF0,0x30,0x3D,0x80,
0x00,0x00,0x01,0xBF,0xF0,0x7C,0xF9,0x80,0x00,0x00,0x01,0xFF,0xF0,0xFF,0xF3,0x00,
0x00,0x00,0x01,0xFF,0xE1,0xFF,0x8E,0x00,0x00,0x00,0x01,0xEF,0x7F,0xFF,0xFC,0x00,
0x00,0x00,0x00,0xEE,0x7F,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/*"C:\Users\lx\Desktop\0604abee9b593c0e2bf6df460d4623d8.bmp",0*/


const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
const byte encoder0pinB = 3;//B pin -> the digital pin 3
int E_left =5; //L298P直流电机驱动板的使能端口连接到数字接口5
int M_left =4; //L298P直流电机驱动板的转向端口连接到数字接口4
int button =7; //控制电机转动按钮7
int i =0;
byte encoder0PinALast;
double duration,abs_duration;//the number of the pulses
boolean Direction;//the rotation direction 
boolean result;

double val_output;//用于提供给电机PWM功率值。
double Setpoint;
double Kp=0.6, Ki=5, Kd=0;  
PID myPID(&abs_duration, &val_output, &Setpoint, Kp, Ki, Kd, DIRECT); 
static unsigned long currentTime = 0; 
int buttonState =0;
int times =0;
int iotState =0;


SoftwareSerial softSerial(10,11);
//生成OBLOQ对象,参数:串口指针,wifiSsid, WifiPwd, iotId, iotPwd
//Generate OBLOQ object, parameters: serial pointer, wifiSsid, WifiPwd, iotId, iotPwd
Obloq olq(&softSerial,"DFRobot-guest","dfrobot@2017","xxxxxxxxxx","xxxxxxxxxx");
const String devTopic = "xxxxxxxxxx";
const String devTopic2 = "xxxxxxxxxx";

void setup()
{  
   Serial.begin(9600);//Initialize the serial port
   pinMode(M_left, OUTPUT);   //L298P直流电机驱动板的控制端口设置为输出模式
   pinMode(E_left, OUTPUT); 
   Setpoint =80;  //设置PID的输出值
   myPID.SetMode(AUTOMATIC);//设置PID为自动模式
   myPID.SetSampleTime(20);//设置PID采样频率为100ms
   EncoderInit();//Initialize the module
   pinMode(button, INPUT);
   softSerial.begin(9600);
   olq.setMsgHandle(msgHandle);//注册消息回调函数 register message callback function
   olq.subscribe(devTopic2); //监听设备 Subscribe topic
}
 
void loop()
{   
    Serial.print(iotState);
    abs_duration=abs(duration);
    result=myPID.Compute();//PID转换完成返回值为1
    if(result)
    {
      Serial.print("Pluse: ");
      Serial.println(duration); 
      duration = 0; //计数清零等待下次计数
    }
    millis();
    olq.update();
    u8g.firstPage();
    do 
      {
   //     u8g.setFont(u8g_font_04b_03b_short); // 字体设置
   //     u8g.drawStr(36,48,times);
        u8g.setColorIndex(1);
        drawSTART();
        drawURL();
        u8g.setFont(u8g_font_unifont);
        u8g.setPrintPos(48,64);
        u8g.print(times);
      } while ( u8g.nextPage() );
    if(iotState == 1)
    {
      advance();
    }
    if(iotState == 0)
    {
      Stop();
    }
    if(iotState == 2)
    {
    if(digitalRead(button)  == HIGH)
    {
      buttonState =1;
    }
    if(i>=10)
    {
      Stop();//电机停止
      olq.publish("HkHyId8rX",String(times++));
      delay(5000);
      buttonState =0;
      i=0;
    }
    if(i<10)
      {
        if(buttonState ==1)
        {
          i++;
          Serial.println(i); 
          advance();//电机正转  
        }
      }
    else
      {
        Stop();//电机停止
      }
    }
}
 
void EncoderInit()
{
  Direction = true;//default -> Forward  
  pinMode(encoder0pinB,INPUT);  
  attachInterrupt(0, wheelSpeed, CHANGE);
}
 
void wheelSpeed()
{
  int Lstate = digitalRead(encoder0pinA);
  if((encoder0PinALast == LOW) && Lstate==HIGH)
  {
    int val = digitalRead(encoder0pinB);
    if(val == LOW && Direction)
    {
      Direction = false; //Reverse
    }
    else if(val == HIGH && !Direction)
    {
      Direction = true;  //Forward
    }
  }
  encoder0PinALast = Lstate;
 
  if(!Direction)  duration++;
  else  duration--;

}
void advance()//电机正转
{
     digitalWrite(M_left,LOW);
     analogWrite(E_left,val_output);
}
void back()//电机反转
{
     digitalWrite(M_left,HIGH);
     analogWrite(E_left,val_output);
}

void Stop()//电机停止
{
     digitalWrite(E_left, LOW); 
} 

void drawSTART(void)
{
  u8g.drawBitmapP(0,16,2,16,str_zong);u8g.drawBitmapP(16,16,2,16,str_liang);u8g.drawBitmapP(32,16,2,16,str_m);u8g.drawBitmapP(64,16,1,16,str_g);
  u8g.drawBitmapP(0,32,2,16,str_shi);u8g.drawBitmapP(16,32,2,16,str_liang);u8g.drawBitmapP(32,32,2,16,str_m);u8g.drawBitmapP(64,32,1,16,str_g);
  u8g.drawBitmapP(0,48,2,16,str_ci);u8g.drawBitmapP(16,48,2,16,str_shu);u8g.drawBitmapP(32,48,2,16,str_m);
  u8g.drawBitmapP(64,16,8,64,str_cat);
}


void drawURL(void)
{
#ifndef MINI_LOGO
  u8g.setFont(u8g_font_4x6);
  if ( u8g.getHeight() < 59 )
  {
    u8g.drawStr(53, 9, "www.dfrobot");
    u8g.drawStr(77, 18, ".com.cn");
  }
  else
  {
    u8g.drawStr(53,8, "www.dfrobot.com.cn");
  }
#endif
}

void msgHandle(const String& topic,const String& message)
{
      if(devTopic2 == topic)
    {
        if(message == "1")
          iotState = 1;
        else if(message == "0")
          iotState = 0;
        else
          iotState = 2;
    }
}
  

总结

这一版的猫粮机还是有很多缺陷的,比如没有留更换电池的接口,结构还不够紧凑等。接下来会不断的改进这款猫粮机的,为大家的猫主子提供更好的投喂机器!

资料

猫粮机激光切割木板资料:链接:https://pan.baidu.com/s/18wUuxueBqd2N9shGOfW4hg 提取码:96jj

3D打印件资料:链接:https://pan.baidu.com/s/1K5I8p9uzllz6FDyLMTp81g 提取码:j1co

评论

user-avatar
  • DFBJ9p-sPLV

    DFBJ9p-sPLV2019.03.10

    为什么链接打不开呢

    0
    • Fish

      Fish2018.12.10

      r

      0
      • Fish

        Fish2018.12.10

        r

        0
        • DFBJyrxBnnm

          DFBJyrxBnnm2018.11.04

          哇 好棒

          0
          • ASH腻

            ASH腻2018.10.30

            万事俱备 只差猫主子

            0
            • fpqEu0X2LC7y

              fpqEu0X2LC7y2018.10.23

              大气!

              0
              • 管理员

                管理员2018.10.22

                有意思

                0