智能电饭煲
一、 简介
1、作品构思
? 我们团队参与到OH成长计划的智能电饭煲开发后,便开始构思如何实现自动洗米、煮饭、加热这一系列流程,经过几天的讨论,最终我们选择电机转动产生的气流进行洗米、舵机转动控制开关加热、利用继电器控制水泵加适量水进行煮饭流程,统一完模型搭建后,我们便开始全身心投入产品开发过程中,我们组一个六个人,分工很简单
任务表 |
---|
设备开发(电路搭建,硬件调试) | 应用开发(数字管家,日程管理) | 服务端开发(服务器搭建,华为云上产品创建) | 模型搭建(电饭煲初代模型搭建) | NFC功能开发(负责NFC标签创建) | 资料收集(负责收集我们开发文档,协调组内进度) |
2、实践过程
购买搭建电路所需的各个模块,搭建模型的各类器材
①用到的设备产品: BearPi-HM Nano
设备电路搭建用到的器件:杜邦线(若干),继电器(四个),面包板(一个),MG90型号舵机(2个),MG955型号舵机(3个),鼓风机(2个),抽水泵(一个),连接管(若干),
? 锂电池(一对),锂电池电源管理(一个),电压值显示(一个),家用电饭煲(一个),亚克力板(若干)
模型搭建
算法流程
流速测量:
一、输米速
次数 | 流量(g) | 时间t(s) | 流速v2(g/s) |
---|
1 | 1000 | 12.2 | 81.9 | 11.4 | 87.7 | | | 11.8 | 84.7 | | | 2 | 800 | 9.3 | 86.0 | 8.4 | 95.2 | | | 8.9 | 89.8 | | | 3 | 600 | 7.5 | 80 | 7.3 | 82.19 | | | 6.8 | 88.8 | | | 4 | 400 | 4.7 | 85.1 | 5.6 | 71.4 | | | 5.1 | 78.4 | | | 5 | 200 | 3.9 | 51.2 | 2.8 | 71.4 | | | 3.4 | 58.8 | | | v2均值 | 79.5 g/s | | |
二、输水速
次数 | 流量(mL) | 时间t(s) | 流速v1(mL/s) |
---|
1 | 900 | 31.4 | 28.6 | 2 | 800 | 27.2 | 29.4 | 3 | 700 | 23.7 | 29.5 | 4 | 600 | 21.0 | 28.5 | 5 | 500 | 17.4 | 28.7 | 6 | 400 | 13.7 | 29.2 | V1均值 | 28.9 mL/s | | |
二、技术方案
1、硬件介绍
? 本项目是基于Bearpi开发板作为主控的智能电饭煲,模型搭建利用的是亚克力板,该设备内主要由MG955舵机、MG90舵机、继电器、锂电池管理模块和小型水泵组成
设备开发器件介绍
杜邦线: 连通电路,方便插接
面包板:接通多个端口,实现多端电源供电
锂电池:提供电源,使能舵机,电机
锂电池充电模块:节能环保,升压,给电源提供充足动力
继电器:
Mg90舵机:
MG955舵机:
2、软件部分
1、设备准备
预装HarmonyOS手机一台
2、设备配网
1、在设备上电前需准备好安装了数字管家应用的HarmonyOS手机,详情见数字管家应用开发, 并在设置中开启手机的NFC功能;
2、写设备NFC标签,详细操作见设备NFC标签指导文档;
3、烧录完成后,上电。开发者在观察开发板上状态LED灯以8Hz的频率闪烁时,将手机上半部靠近开发板NFC标签处;
4、无需任何操作手机将自动拉起数字管家应用并进入配网状态,配网过程中无需输入热点账号密码。 具体无感配网相关流程参考 无感配网指南
3、操作体验
1、设备控制
2、配网完成后,数字管家应用会自动进入智能电饭煲的控制页面,通过控制页面可以实现对智能电饭煲加米、洗米、煮饭的控制。
3、预约做饭
4、使用者可以通过控制页面进入智能电饭煲控制页面或者数字管家日程管理页面进行日程管理,具体做法如下:
l 进入日程管理页面后对日程命名并添加通知成员与智能电饭煲设备。
l 选择做饭的起止时间。
l 选择提示方式与提醒重复时间。
3、服务器部分
前期准备
1、注册华为云账号并且实名认证(略)
2、购买华为弹性云服务器(其他也可)
基础环境配置(可跳过)
1、查看系统版本
不符合可切换系统版本
放开相应端口(这里放开全部端口)
记住上面输入的密码
2、下载mobaxterm终端并安装
3、连接服务器
注:连接前要在华为云安全组开发相应端口,不然可能连接失败
安装和部署数字管家服务端
1)mysql5.7安装
sudo apt install mysql-server
openjdk 1.8 安装
sudo apt-get install openjdk-8-jdk
设置无密码登录
添加 skip-grant-tables
重启mysql
service mysql restart
进入mysql
mysql -u root -p
输入后回车
更改密码
mysql> use mysql;
mysql>flush privileges;
mysql>UPDATE user SET authentication_string="" WHERE user="root";
mysql>flush privileges;
mysql>ALTER user 'root'@'localhost' IDENTIFIED BY 'abc123456@qq.com';
注:密码格式有要求(必须包括大小写,数字和特殊字符)
以上完成后输入quit 退出 mysql 交互模式,去掉之前加的 skip-grant-tables,再重启 mysql
2)RabbitMQ 3.6.10(安装)
由于RabbitMQ采用的Erlang语言编写的,故需先安装Erlang
1:在系统中加入 erlang apt 仓库
wget https:
sudo dpkg -i erlang-solutions_1.0_all.deb
2:修改 Erlang 镜像地址,默认的下载速度特别慢。
vi /etc/apt/sources.list.d/erlang-solutions.list
3:把里面默认值替换为
deb https:
4:更新软件列表
sudo apt-get update
5:安装Erlang
sudo apt-get install erlang erlang-nox
安装RabbitMq
1:添加rabbitmq的仓库列表配置文件
echo 'deb http:
2:加入rabbitmq signing key
wget -O- https:
3:更新软件列表
sudo apt-get update
4:安装RabbitMq(安装完之后rabbitmq默认已启动)
sudo apt-get install rabbitmq-server
5:启用web管理插件
sudo rabbitmq-plugins enable rabbitmq_management
6:重启rabbitmq服务
sudo systemctl restart rabbitmq-server
安装完成后在浏览器中输入自己的id和端口就可以看到管理页面了
rabbitmq 添加用户以及权限
1:新增一个用户
rabbitmqctl add_user root root
2:为root用户设置权限所有权限
rabbitmqctl set_permissions -p / root “." ".” “.*”
3:设置root用户为管理员角色
rabbitmqctl set_user_tags root administrator
三、代码解析
1、创建主任务函数
static void IotMainEntry(void)
{
osThreadAttr_t attr;
RaiseLog(LOG_LEVEL_INFO, "DATA:%s Time:%s \r\n",__FUNCTION__, __DATE__, __TIME__);
memset(&g_appController, 0x00, sizeof(g_appController));
g_appController.sensorTaskEvent = osEventFlagsNew(NULL);
if ( g_appController.sensorTaskEvent == NULL) {
return;
}
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE;
attr.priority = CONFIG_TASK_MAIN_PRIOR;
attr.name = "IoTMain";
(void) osThreadNew((osThreadFunc_t)IotMainTaskEntry, NULL, (const osThreadAttr_t *)&attr);
return;
}
APP_FEATURE_INIT(IotMainEntry);
2、碰一碰配网代码解析
static void IotMainTaskEntry(const void *arg)
{
osThreadAttr_t attr;
NfcInfo nfcInfo;
(void)arg;
char ssid[BUFF_SIZE] = {0};
char pwd[BUFF_SIZE] = {0};
int ret = 0;
BOARD_InitPwmLed();
FlowerInit();
BOARD_InitWifi();
IOT_ScheduleInit();
ret = Board_IsButtonPressedF2();
osDelay(MAIN_TASK_DELAY_TICKS);
Board_InitButtonF1(BoardLedButtonCallbackF1, NULL);
Board_InitButtonF2(BoardLedButtonCallbackF2, NULL);
LedFlashFrequencySet(CONFIG_FLASHLED_FRENETCONFIG);
nfcInfo.deviceID = "621068a3de9933029be8e65b_RiceCooker";
nfcInfo.devicePWD = "12345678";
if (ret)
{
RaiseLog(LOG_LEVEL_INFO, "Netconfig Button has pressed! \n");
if (BOARD_NAN_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0)
{
RaiseLog(LOG_LEVEL_ERR, "BOARD_NetCfgStartConfig failed! \n");
return;
}
else
{
ret = AFTER_NETCFG_ACTION;
printf("BOARD_NetCfgStartConfig success! \n");
}
}
else
{
ret = IotWifiInfo_get(ssid, sizeof(ssid), pwd, sizeof(pwd));
if (ret == 0)
{
if (BOARD_NAN_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0)
{
RaiseLog(LOG_LEVEL_ERR, "BOARD_NetCfgStartConfig failed! \n");
return;
}
else
{
ret = AFTER_NETCFG_ACTION;
printf("BOARD_NetCfgStartConfig success! \n");
}
}
}
LedFlashFrequencySet(CONFIG_FLASHLED_FREWIFI);
if (BOARD_ConnectWifi(ssid, pwd) != 0)
{
RaiseLog(LOG_LEVEL_ERR, "BOARD_ConnectWifi failed! \n");
if (ret == AFTER_NETCFG_ACTION)
{
NotifyNetCfgResult(NETCFG_DEV_INFO_INVALID);
}
hi_hard_reboot(HI_SYS_REBOOT_CAUSE_CMD);
return;
}
if (ret == AFTER_NETCFG_ACTION) {
RaiseLog(LOG_LEVEL_DEBUG, "Connect wifi success ! \n");
NotifyNetCfgResult(NETCFG_OK);
osDelay(MAIN_TASK_DELAY_TICKS);
RaiseLog(LOG_LEVEL_DEBUG, "StopNetCfg wifi success ! \n");
StopNetCfg();
IotWifiInfo_set(ssid, pwd);
}
LedFlashFrequencySet(CONFIG_FLASHLED_FRECLOUD);
RtcTimeUpdate();
if (CLOUD_Init() != 0) {
return;
}
if (CLOUD_Connect(nfcInfo.deviceID, nfcInfo.devicePWD, \
CONFIG_CLOUD_DEFAULT_SERVERIP, CONFIG_CLOUD_DEFAULT_SERVERPORT) != 0) {
return;
}
LedFlashFrequencySet(CONFIG_FLASHLED_WORKSWELL);
g_appController.timeID = osTimerNew(&TimerHandle, osTimerPeriodic, NULL, NULL);
osTimerStart(g_appController.timeID, TIMER_TICK_NUM);
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = CONFIG_TASK_DEFAULT_STACKSIZE;
attr.priority = CONFIG_TASK_DEFAULT_PRIOR;
attr.name = "DataCollectAndReport";
if (osThreadNew((osThreadFunc_t)DataCollectAndReport, NULL, (const osThreadAttr_t *)&attr) == NULL) {
return;
}
attr.name = "RiceShedule";
if (osThreadNew((osThreadFunc_t)RiceShedule, NULL, (const osThreadAttr_t *)&attr) == NULL) {
return;
}
return;
}
3、日程管理代码
static void RiceShedule(void)
{
int startSecondInDay = 0;
int endSecondInDay = 0;
CommandParamSetControlMotor motorStatus, lastMotorStatus;
while(1) {
osDelay(Time2Tick(CN_MINISECONDS_IN_SECOND));
RaiseLog(LOG_LEVEL_INFO, "dayTime --> %02d:%02d:%02d \n", g_appController.curSecondsInDay / CN_SECONDS_IN_HOUR,\
(g_appController.curSecondsInDay % CN_SECONDS_IN_HOUR) / CN_SECONDS_IN_MINUTE,\
g_appController.curSecondsInDay % CN_SECONDS_IN_MINUTE);
if (g_appController.curSecondsInDay >= CN_SECONS_IN_DAY) {
g_appController.curSecondsInDay = 0;
g_appController.curDay++;
g_appController.lightManual = false;
if (g_appController.curDay >= EN_DAYALL) {
g_appController.curDay = EN_MONDAY;
}
IOT_ScheduleSetUpdate(1);
}
if (IOT_ScheduleIsUpdate(g_appController.curDay, g_appController.curSecondsInDay)) {
if (g_appController.timerFlag) {
g_appController.executeTime = 0;
g_appController.timerFlag = 0;
if (g_appController.mainFlowerStatus == CN_BOARD_SWITCH_ON) {
g_appController.mainFlowerStatus = CN_BOARD_SWITCH_OFF;
osEventFlagsSet(g_appController.sensorTaskEvent, CN_FLOWER_EVENT_SETSTATUS);
}
}
startSecondInDay = IOT_ScheduleGetStartTime();
endSecondInDay = startSecondInDay + IOT_ScheduleGetDurationTime();
IOT_ScheduleGetCommand(&(motorStatus.status), &(motorStatus.capacity));
}
if (g_appController.timerFlag == 0) {
RaiseLog(LOG_LEVEL_INFO, "start:%d end:%d cur:%d",
startSecondInDay, endSecondInDay, g_appController.curSecondsInDay);
if ((g_appController.curSecondsInDay >= startSecondInDay) && \
(g_appController.curSecondsInDay < endSecondInDay)) {
lastMotorStatus.status = g_appController.mainFlowerStatus;
g_appController.mainFlowerStatus = motorStatus.status;
if (g_appController.mainFlowerStatus != lastMotorStatus.status) {
RaiseLog(LOG_LEVEL_INFO, "Triggering");
g_appController.mainFlowerStatus = CN_BOARD_SWITCH_ON;
osEventFlagsSet(g_appController.sensorTaskEvent, CN_FLOWER_EVENT_SETSTATUS);
}
g_appController.executeTime = endSecondInDay - g_appController.curSecondsInDay;
g_appController.timerFlag = 1;
}
}
else
{
if (g_appController.executeTime == 0)
{
if (g_appController.mainFlowerStatus != CN_BOARD_SWITCH_OFF)
{
g_appController.mainFlowerStatus = CN_BOARD_SWITCH_OFF;
osEventFlagsSet(g_appController.sensorTaskEvent, CN_FLOWER_EVENT_SETSTATUS);
}
IOT_ScheduleSetUpdate(1);
startSecondInDay = 0;
endSecondInDay = 0;
memset(&lastMotorStatus, 0x00, sizeof(lastMotorStatus));
g_appController.timerFlag = 0;
}
}
}
return;
}
4、华为云平台连接服务
/**
* @brief 回调函数,用于处理云平台下发的命令
* @param command 表示云平台下发的命令
* @param value 表示命令对应的参数
* @return 返回 0 成功而 -1 失败
*/
int IotProfile_CommandCallback(int command, void *buf)
{
CommandParamSetShedule setSheduleParam;
CommandParamSetControlMotor setControlMotorParam;
CLOUD_CommandType cmd = (CLOUD_CommandType)command;
/**
* 这里我们只处理云平台下发的控制煮饭的命令,
* 值应为 CN_BOARD_SWITCH_ON 或 CN_BOARD_SWITCH_OFF
*/
if (cmd == CLOUD_COMMAND_CONTROLMOTOR)
{
setControlMotorParam = *(CommandParamSetControlMotor *)buf;
if (g_appController.mainFlowerStatus != setControlMotorParam.status)
{
g_appController.mainFlowerStatus = setControlMotorParam.status;
g_appController.lightManual = true;
if (g_appController.mainFlowerStatus == CN_BOARD_SWITCH_ON)
{
g_appController.executeTime = setControlMotorParam.capacity / 10;
g_appController.timerFlag = 1;
}
RaiseLog(LOG_LEVEL_INFO, "setControlMotor:%d\r\n", setControlMotorParam.status);
osEventFlagsSet(g_appController.sensorTaskEvent, CN_FLOWER_EVENT_SETSTATUS);
}
return 0;
}
else if (cmd == CLOUD_COMMAND_SETSHEDULE)
{
setSheduleParam = *(CommandParamSetShedule *)buf;
RaiseLog(LOG_LEVEL_INFO, "setshedule:day:%d hour:%d minute:%d duration:%d \r\n", \
setSheduleParam.day,setSheduleParam.startHour,setSheduleParam.startMinute, setSheduleParam.duration);
return UpdateShedule(&setSheduleParam);
}
return -1;
}
5、控制煮饭启动
static int start_rice()
{
//气压舵机(MG90)状态为90度:打开盖扣
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(8, 1);
hi_udelay(1500);
IoTGpioSetOutputVal(8, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-1500);
}
hi_udelay(10000);
//开盖舵机(MG955)旋转开锅
int a =0;
while(a<4)
{
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(7, 1);
hi_udelay(1000);
IoTGpioSetOutputVal(7, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-1000);
}
a++;
}
hi_udelay(10000);
//输送舵机(MG955)转动出仓
for (int i = 1; i <=20; i++)
{
IoTGpioSetOutputVal(5, 1);
hi_udelay(2000);
IoTGpioSetOutputVal(5, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-2000);
}
hi_udelay(10000);
//水泵直流电机启动
IoTGpioSetOutputVal(6, 1);
hi_udelay(5000000);
IoTGpioSetOutputVal(6, 0);
hi_udelay(5000000);
//空洗直流电机初始为1
IoTGpioSetOutputVal(3, 1);
hi_udelay(10000000);
//放米舵机(MG90)转到90°:打开仓门
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(2, 1);
hi_udelay(1500);
IoTGpioSetOutputVal(2, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-1500);
}
hi_udelay(10000);
osDelay(500);
//放米舵机(MG90)转到0°:关闭仓门
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(2, 1);
hi_udelay(500);
IoTGpioSetOutputVal(2, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-500);
}
hi_udelay(10000);
//空洗直流电机初始为0
IoTGpioSetOutputVal(3, 0);
hi_udelay(10000000);
//开盖舵机(MG955)旋转关锅
int c =0;
while(c<2)
{
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(7, 1);
hi_udelay(2000);
IoTGpioSetOutputVal(7, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-2000);
}
c++;
}
hi_udelay(10000);
//气压舵机(MG90)状态为90度:关闭盖扣
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(8, 1);
hi_udelay(500);
IoTGpioSetOutputVal(8, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-500);
}
hi_udelay(10000);
//煮饭舵机(MG995)转动(按下按钮)
int j = 0;
while(j<2)
{
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(9, 1);
hi_udelay(1000);
IoTGpioSetOutputVal(9, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-1000);
}
hi_udelay(10000);
j++;
}
//煮饭舵机(MG995)转回(松开按钮)
int b = 0;
while(b<1)
{
for (int i = 1; i <=20 ; i++)
{
IoTGpioSetOutputVal(9, 1);
hi_udelay(2000);
IoTGpioSetOutputVal(9, 0);
hi_udelay(THE_CYCLES_OF_PWM_CONTROL-2000);
}
hi_udelay(10000);
b++;
}
return 0;
}
四、实物操作体验
|