宠物喂食器,基于涂鸦智能的解决方案

  • 作品描述
  • 作品介绍
    • 硬件部分
    • 软件部分
  • 开发流程
    • 代码编写
      • 1. 产品创建
      • 2. MCU SDK 移植
      • 3. 时间系统实现
      • 4. 快速喂食功能实现
      • 5. 余粮检测功能
      • 6. 已出粮剩余量检测功能
      • 7. 计划喂食功能实现
      • 8. 手动喂食功能实现
      • 9. 小夜灯功能实现
      • 10. 语音控制功能实现
    • 外壳制作
      • 1. 粮仓制作
      • 2. 重量检测平台制作
      • 3. 喂食波轮制作
      • 4. 主体结构制作
      • 5. 完成效果

本项目通信板、电源板、驱动板、涂鸦智能APP以及物联网云平台由 涂鸦智能提供支持。
本文章允许涂鸦智能转载使用。

作品描述

pet_feeder,一款宠物喂食器,基于涂鸦IoT平台及三明治开发板开发。
项目地址:
gitee: pet_feeder
github: pet_feeder

作品介绍

硬件部分

主控:stm32f103芯片;
通信板:涂鸦VWXR2 Wi-Fi通信板;
物联网云平台:接入涂鸦IoT云平台;
喂食器执行电机:42微型步进电机;
电机驱动:RQSM240驱动器;
余粮和出粮检测模块:电阻应变片式压力传感器+HX711AD模块;
小夜灯:普通LED灯;
手机控制端:涂鸦智能APP;
外壳:自主DIY.
硬件框架

软件部分

操作系统:rt-thread-3.1.3-nano;
云端对接方式:涂鸦标准模组MCU SDK;
通信模组固件:涂鸦通用Wi-Fi通信模块固件;
MCU与模组通信方式:USART;
语音平台:涂鸦小智管家;
功能模块
线程
time_sys_thread: 时间系统线程,为计划喂食功能提供当前时间,通过涂鸦IoT平台校准时间;
wifi_usart_service_thread: 串口通信服务线程,用于处理MCU与同学模组之间的通信数据;
granary_weight_thread: 余粮检测线程,检测当前粮桶余粮情况,每变化50g向云端上报一次;
export_weight_thread: 出粮检测线程,检测当前已出粮的剩余重量,每变化50g向云端上报一次;
quick_feed_thread: 快速喂食线程,提供快速喂食服务,支持本地按键控制和手机APP控制,按一次或点击一次喂食一份;
key_scan_thread: 按键检测线程,检测快速喂食控制按钮是否被按下;
信号量:
Quick_feed_sem: 记录按键按下次数,或APP点击次数,为快速喂食提供信号,实现连续多份快速喂食;
软件框架

开发流程

代码编写

1. 产品创建

参考涂鸦官方教程产品创建流程

2. MCU SDK 移植

参考涂鸦官方教程MCU SDK 移植

3. 时间系统实现

时间系统主要服务于计划喂食功能,而喂食计划由星期、时、分、喂食量构成。因此时间系统不需要过于细致的功能,能提供所需的数据即可,必要时可通过涂鸦云平台进行更新校准。通过rt-thread提供的ms级延时函数rt_thread_mdeay()实现时间秒针,进而实现时间系统功能。每分钟检查一次喂食计划,每小时校准一下时间。具体实现方式如下:

/*** @brief  时间系统* @param  Null* @return Null* @note   Null*/
void time_sys(void* parameter)
{time_now.year = 2020;time_now.month = 1;time_now.day = 1;time_now.hour = 0;time_now.min = 0;time_now.sec = 0;time_now.week = 1;time_now.updata_state = ERROR;while(1){rt_thread_mdelay(1000);time_now.sec ++;if(time_now.updata_state != SUCCESS){mcu_get_system_time();//更新时间日期get_nearly_meal_plan();}if(time_now.sec >= 60){time_now.sec = 0;time_now.min ++;meal_plan_check();//喂食计划检测if(time_now.min >= 60){time_now.min = 0;time_now.hour ++;time_now.updata_state = ERROR;//日期的更新靠联网实现if(time_now.hour >= 24){time_now.hour = 0;time_now.week++;if(time_now.week >= 8){time_now.week = 1;}time_now.updata_state = ERROR;//日期的更新靠联网实现 }}}}
}

4. 快速喂食功能实现

快速喂食功能提供两种控制方式,手动按键与APP控制。APP通过云平台下发数据后进入功能点下发处理函数:

/*****************************************************************************
函数名称 : dp_download_quick_feed_handle
功能描述 : 针对DPID_QUICK_FEED的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_quick_feed_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为BOOLunsigned char ret;//0:关/1:开unsigned char quick_feed;quick_feed = mcu_get_dp_download_bool(value,length);if(quick_feed == 0){//开关关}else {//开关开feed(1);}//处理完DP数据后应有反馈ret = mcu_dp_bool_update(DPID_QUICK_FEED,quick_feed);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}

本地按键按下后被按键检测线程捕获进而向快速喂食线程释放信号量:

/*** @brief  按键1扫描* @param  Null* @return Null* @note   Null*/
void key1_scan(void* parameter)
{while(1){rt_thread_delay(50);if( GPIO_ReadInputDataBit(KEY1_INT_GPIO_PORT, KEY1_INT_GPIO_PIN) == KEY_ON ){// 松手检测while( GPIO_ReadInputDataBit(KEY1_INT_GPIO_PORT, KEY1_INT_GPIO_PIN) == KEY_ON );rt_sem_release(quick_feed_sem);}}
}

功能点下发处理函数和快速喂食线程最终都调用喂食执行函数void feed(uint8_t n)通过步进电机驱动实现喂食。

/*** @brief  反转n圈* @param  n:转动圈数* @retval 无*/
void step_motor_reverse(uint8_t n)
{step_motor_enable();set_dir_reverse();for(uint8_t i=0; i<n; i++){step_motor_rotate_1();}
}

步进电机执行喂食需要一定的时间,如果多次按下按键可能会被遗漏执行,这里采用信号量决绝该问题。
步进电机初始化如下所示:

/*** @brief  初始化控制步进电机的IO* @param  无* @retval 无*/
void STEP_MOTOR_GPIO_Config(void)
{       /*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启步进电机相关的GPIO外设时钟*/RCC_APB2PeriphClockCmd( STEP_MOTOR_DIR_GPIO_CLK | STEP_MOTOR_PLUSE_GPIO_CLK | STEP_MOTOR_OFFLINE_GPIO_CLK, ENABLE);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = STEP_MOTOR_DIR_GPIO_PIN;   /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/GPIO_Init(STEP_MOTOR_DIR_GPIO_PORT, &GPIO_InitStructure);   /*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = STEP_MOTOR_PLUSE_GPIO_PIN;/*调用库函数,初始化GPIO*/GPIO_Init(STEP_MOTOR_PLUSE_GPIO_PORT, &GPIO_InitStructure);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = STEP_MOTOR_OFFLINE_GPIO_PIN;/*调用库函数,初始化GPIOF*/GPIO_Init(STEP_MOTOR_OFFLINE_GPIO_PORT, &GPIO_InitStructure);/* 使能步进电机  */GPIO_SetBits(STEP_MOTOR_OFFLINE_GPIO_PORT, STEP_MOTOR_OFFLINE_GPIO_PIN);/* 设置转动方向 */GPIO_SetBits(STEP_MOTOR_DIR_GPIO_PORT, STEP_MOTOR_DIR_GPIO_PIN);
}

5. 余粮检测功能

HX711AD模块初始化:

/*** @brief  初始化控制hx711的IO* @param  无* @retval 无*/
void HX711_GRANARY_GPIO_Config(void)
{       /*定义一个GPIO_InitTypeDef类型的结构体*/GPIO_InitTypeDef GPIO_InitStructure;/*开启hx711相关的GPIO外设时钟*/RCC_APB2PeriphClockCmd( HX711_GRANARY_DOUT_GPIO_CLK | HX711_GRANARY_SCK_GPIO_CLK, ENABLE);/*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = HX711_GRANARY_DOUT_GPIO_PIN;   /*设置引脚模式为浮空输入*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   /*设置引脚速率为50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化GPIO*/GPIO_Init(HX711_GRANARY_DOUT_GPIO_PORT, &GPIO_InitStructure);    /*设置引脚模式为通用推挽输出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*选择要控制的GPIO引脚*/GPIO_InitStructure.GPIO_Pin = HX711_GRANARY_SCK_GPIO_PIN;/*调用库函数,初始化GPIO*/GPIO_Init(HX711_GRANARY_SCK_GPIO_PORT, &GPIO_InitStructure);
}

读取压力传感器值:

/*** @brief  读取HX711* @param  Null* @return 压力传感器值* @note   Null*/
uint16_t hx711_granary_read(void)   //增益128
{uint32_t count;uint16_t granary_weight;uint8_t i; set_hx711_dout(); rt_thread_delay(5);reset_hx711_sck();count=0;while(read_dout());for(i=0;i<24;i++){ set_hx711_sck(); count=count<<1; reset_hx711_sck(); if(read_dout())count++; } set_hx711_sck(); count=count^0x800000;//第25个脉冲下降沿来时,转换数据rt_thread_delay(5);reset_hx711_sck(); granary_weight = (unsigned long)((float)count/gapvalue_granary);return(granary_weight);
}

在线程中实现重量检测,余粮剩余情况采用百分制表示,定义3Kg,full_granary=3000为满箱状态。余粮每变化1% 向云端上报一次。

/*** @brief  粮桶余粮重量检测* @param  Null* @return Null* @note   Null*/
void granary_weight(void* parameter)
{uint32_t tem, granary_weight, diff;uint8_t granary_weight_percent;while(1){rt_thread_delay(50);tem = hx711_granary_read() - granary_peel;if(tem > granary_weight){diff = tem - granary_weight;}else{diff = granary_weight - tem;}if(diff > full_granary/100){granary_weight = tem;if( granary_weight >= full_granary ){granary_weight_percent = 100;mcu_dp_value_update(DPID_SURPLUS_GRAIN, granary_weight_percent);}else{granary_weight_percent = (granary_weight) / (full_granary/100);mcu_dp_value_update(DPID_SURPLUS_GRAIN, granary_weight_percent);}}}
}

6. 已出粮剩余量检测功能

HX711初始化和压力传感器值读取方法与余粮检测功能中相似,在此不再赘述。已出粮剩余情况采用重量表示,没变化50g向云端上报一次。

/*** @brief  已出粮剩余重量检测* @param  Null* @return Null* @note   Null*/
void export_weight(void* parameter)
{uint32_t tem, export_weight, diff;while(1){rt_thread_delay(50);tem = hx711_export_read() - export_peel;if(tem > export_weight){diff = tem - export_weight;}else{diff = export_weight - tem;}if(diff > 50){export_weight = tem;mcu_dp_value_update(DPID_WEIGHT, export_weight);}}
}

7. 计划喂食功能实现

喂食计划下发后进入功能点下发处理函数,在此处根据通讯协议对喂食计划进行解析提取并存入meal_plan结构体中。

/*****************************************************************************
函数名称 : dp_download_meal_plan_handle
功能描述 : 针对DPID_MEAL_PLAN的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_meal_plan_handle(const unsigned char value[], unsigned short length)
{uint8_t i, k=0;//示例:当前DP类型为RAWunsigned char ret;//RAW类型数据处理meal_plan_amount = 0;for(i=0; i<length/5; i++){if((uint16_t)value[5*(i+1)-1] != 0){meal_plan_amount++;meal_plan[k].week   = value[5*i+0];meal_plan[k].hour   = value[5*i+1];meal_plan[k].min    = value[5*i+2];meal_plan[k].amount = value[5*i+3];k++;}}//    for(i=0; i<meal_plan_amount; i++)
//  {//      rt_kprintf("meal plan %d: %d %d %d %d\n", i, meal_plan[i].week, meal_plan[i].hour, meal_plan[i].min,meal_plan[i].amount);
//  }
//  rt_kprintf("\n");get_nearly_meal_plan();//处理完DP数据后应有反馈ret = mcu_dp_raw_update(DPID_MEAL_PLAN,value,length);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}

喂食计划需要每分钟都与当前时间进行一次比较以确保喂食计划的执行不被遗漏。然后喂食计划最多可设置10 个,若每次都将10个喂食计划一一与当前时间进行比较将占用较多系统资源。因此在获取全部喂食计划后对最近的一次喂食计划进行提取,这样每次只需将当前时间与进行喂食计划进行对比,大大节约系统资源。最近喂食计划获取方法如下所示:

/*** @brief  获取最近的喂食计划* @param  Null* @return Null* @note   Null*/
void get_nearly_meal_plan(void)
{uint16_t distance, nearly_distance = 24*60;//将当前时间的星期数转换为one-hot型表示方法uint8_t week_day_form = 0x01;week_day_form = week_day_form << (7 - time_now.week);nearly_meal_plan.week = 0x80;//确保日期不是当天的nearly_meal_plan不生效for(uint8_t i=0; i<meal_plan_amount; i++){if( ((week_day_form & meal_plan[i].week) != 0) && (meal_plan[i].hour >= time_now.hour) && (meal_plan[i].min > time_now.min)){distance = (meal_plan[i].hour - time_now.hour)*60 + (meal_plan[i].min - time_now.min);if(distance < nearly_distance){nearly_distance = distance;nearly_meal_plan = meal_plan[i];}}}
}

分别计算喂食计划于当前时间相隔的分钟数,最小的即为最近喂食计划。这里需要注意,当前时间的星期数采用十进制表示而喂食计划的星期数采用one-hot编码,因此在比较时需先进行转化。同时,为避免混淆将星期数最高为初始化为1,表该计划不生效。因为one-hot编码仅适用低7位,十进制表示方法显然也用不到最高位。因此将最高位用于表示喂食计划是否生效不会造成干涉。获取最近喂食后只需在每分钟检查一次是否到达喂食时间即可,当到达喂食计划的时间则调用喂食执行函数进行喂食,实现方法如下:

/*** @brief  喂食计划检查* @param  Null* @return Null* @note   Null*/
static void meal_plan_check(void)
{if(((nearly_meal_plan.week & 0x80) == 0) && time_now.min == nearly_meal_plan.min && time_now.hour == nearly_meal_plan.hour){feed(nearly_meal_plan.amount);get_nearly_meal_plan();}
}

8. 手动喂食功能实现

APP下发手动喂食指令后,下发数据后进入功能点下发处理函数,在此处调用喂食执行函数喂食指定的份数即可,实现方法如下:

/*****************************************************************************
函数名称 : dp_download_manual_feed_handle
功能描述 : 针对DPID_MANUAL_FEED的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_manual_feed_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为VALUEunsigned char ret;unsigned long manual_feed;manual_feed = mcu_get_dp_download_value(value,length);//VALUE类型数据处理feed(manual_feed);//处理完DP数据后应有反馈ret = mcu_dp_value_update(DPID_MANUAL_FEED,manual_feed);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}

9. 小夜灯功能实现

对小夜灯的控制相当于普通GPIO的控制,引脚初始化这里不再赘述。具体控制在功能点下发处理函数 unsigned char dp_download_light_handle(const unsigned char value[], unsigned short length) 实现,其中 LIGHT_ON 和 LIGHT_OFF 为宏定义,实现引脚的高低电平控制。

/*****************************************************************************
函数名称 : dp_download_light_handle
功能描述 : 针对DPID_LIGHT的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_light_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为BOOLunsigned char ret;//0:关/1:开unsigned char light;light = mcu_get_dp_download_bool(value,length);if(light == 0){LIGHT_OFF;}else{LIGHT_ON;}//处理完DP数据后应有反馈ret = mcu_dp_bool_update(DPID_LIGHT,light);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}

10. 语音控制功能实现

涂鸦 VWXR2 Wi-Fi 模组自带两个mic和一个扬声器,只需在涂鸦云平台完成语音配置,使语音与对应的功能点对应起来即可实现喂食器部分功能的语音控制。配置方法如下图所示:

这里配置了三项语音功能,包括小夜灯的开关控制、快速喂食和粮桶余粮查询。
语音模块收到小夜灯的开关控制和快速喂食指令后会按照设置向MCU下发对应的指令,与APP控制相同,语音控制最终也是进入到功能点下发处理函数执行对应的操作。具体实现方式前面已经介绍过。
粮桶余粮为查询类指令,模块收到指令后直接读取粮桶余粮功能点的数据。

外壳制作

1. 粮仓制作

2. 重量检测平台制作

3. 喂食波轮制作

4. 主体结构制作

5. 完成效果



.

宠物喂食器,基于涂鸦智能的解决方案相关推荐

  1. 基于涂鸦智能的宠物喂食器

    基于涂鸦智能的宠物喂食器 基于涂鸦智能的宠物喂食器 项目地址 作品视频 硬件介绍 系统框架 程序编写 1. 产品创建 2. MCU SDK 移植 3.按键选择程序 4.WiFi状态指示灯 5.云端数据 ...

  2. ESP32-C3芯片宠物喂食器应用,智能自动供水供食

    宠物喂食器可用于小猫.小狗等家庭宠物的喂食和供水,能够为宠物饲养者提供极大地方便. 但目前相关喂食器需要通过手动控制来实现宠物喂食,无法进行定时智能供食:需要用手旋转水嘴开关进行宠物喂水,无法根据宠物 ...

  3. 基于涂鸦智能开发的墨水屏座位管理器——2.嵌入式功能实现篇

    随着互联网连接技术的日益普及,以及大众环保意识增强,电子纸显示市场不断发展,墨水屏的应用场景也越来越多.墨水屏座位管理器方案具体功耗低,多节点管控,信息实时同步等特点,可应用于智慧办公,智慧零售,智慧 ...

  4. 涂鸦智能物联网平台初探

    "涂鸦"在国内做智能家居类的物联网智能平台比一般人想象的要早,远早于后来的同类平台诸如阿里云飞燕物联网平台和腾讯物联网平台.在2014年国内掀起智能硬件开发大潮的时候,就已经开始了 ...

  5. 涂鸦智能全功能智慧植物生长系统(硬件)

    在前面,我们分析完市面上的植物生长机,也选了一款植物生长机进行了拆机,接下来我们就开始搭建一个全功能智慧植物生长系统. 我们想要实现的功能有这些: 涂鸦智能APP远程遥控.监测 光照监测 温湿度监测 ...

  6. 开源:纯手工基于小熊派涂鸦三明治模组快速打造一款智能宠物喂食器连载贴(一)

    涂鸦智能最近出了很多产品方案,有相当多的目前已经在业界量产了.本人有幸参与此次涂鸦的DIY宠物喂食器的活动,拿到了涂鸦智能赠送给我的三明治开发板. 如下图所示,包装还是相当精美的. 关于这些开发板的介 ...

  7. 智能宠物喂食器语音芯片应用设计方案(基于唯创语音芯片WT588E02-8S(C001)功能拓展)

    智能宠物喂食器语音芯片应用设计方案(基于唯创语音芯片WT588E02-8S(C001)功能拓展) 概述 本文主要通过使用唯创知音语音芯片扩展目录进行选型微定制,达到节省成本快速选型开发目的的应用介绍. ...

  8. 涂鸦智能宠物喂食器(鱼缸投食器)

    涂鸦智能宠物喂食器(鱼缸投食器) 系统框架 ①涂鸦IOT平台 1.创建产品 1.进入IOT平台,注册登录,点击创建产品. 2.选择小家电→宠物喂食器→MCU方案→Wi-fi→输入产品名称.型号 3.添 ...

  9. 基于涂鸦模组和ITOP4412开发板的宠物喂食器

    文章目录 基于涂鸦模组和ITOP4412开发板的宠物喂食器 1.作品描述 2.作品介绍 2.1 开发环境 2.1.1硬件设备 2.2 主要实现的功能 2.3 后续更新 3.开发流程 3.1 使用涂鸦I ...

最新文章

  1. Python之range和xrange的区别
  2. 【解决方案】Expected object of type torch.FloatTensor but found type torch.DoubleTensor
  3. codeforces 521div3(D Cutting Out)java
  4. PowerDesigner基本使用
  5. Scala特质(类似Java中的接口)
  6. matlab 检测gpu,康奈尔大学使用MATLAB进行GPU性能测试
  7. mac电脑下Tomcat和Apach配置流程(超详细)
  8. mysql区分大小写搜索
  9. Ubuntu14.04LTS打造实用的环境
  10. webpack系列-plugin
  11. android 获取mac地址
  12. System76 是如何打造开源硬件的
  13. 免费java模板下载安装_java程序员免费简历模板下载
  14. itest听力答案2020_2020英语一真题和答案
  15. oracle数据库,使用plsql导出表数据缺少空表
  16. linux jnlp显示异常,Web启动异常 JNLP
  17. matlab聚类分析实例的博客,基于Matlab的模糊聚类分析及其应用 含实例应用.pptx
  18. 笔记本电脑开机黑屏只能看到鼠标箭头
  19. XiaomiRouter自学之路(13-U-boot支持web更新firmware功能)
  20. 猿辅导python编程老师面试_猿辅导辅导老师面试一系列的感受

热门文章

  1. Fruity Loops Studio21最新中文版水果音乐制作软件
  2. HTML5设计原理 Jeremy Keith在 Fronteers 2010 上的主题演讲
  3. fatal: cannot create directory at ‘xxxxx‘: Permission denied
  4. ZigBee 3.0实战教程-Silicon Labs EFR32+EmberZnet-2-04:开发环境搭建
  5. 计算机控制机床系统设计,基于线切割机床的电机控制系统设计与实现
  6. EF Core 关联数据
  7. IE浏览器版本判断之 Trident (排版引擎)
  8. 如何保障员工的培训效果
  9. RKMPP库快速上手--(四)MPP编码入门
  10. 橙光游戏2.17 0614 版本操作笔记