智能喂食器远程控制系统:硬件设计与软件实现

摘要:本文深入讲解智能宠物喂食器的硬件设计、固件开发、云端控制、定时计划、食物识别等完整技术方案。


一、产品需求分析

1.1 核心功能

功能 需求描述 技术实现
定时投喂 支持10组定时计划 RTC + Cron表达式
远程控制 APP一键投喂 MQTT指令
精准称重 ±1g精度 HX711 + 称重传感器
食量统计 日/周/月统计 时序数据库
缺粮提醒 低于阈值告警 红外/超声波检测
语音呼唤 主人录音播放 I2S + 功放
食物识别 干粮/湿粮识别 摄像头 + AI
防卡粮 卡粮检测与处理 电流检测 + 反转

二、硬件设计

2.1 系统框图

复制代码
┌─────────────────────────────────────────────────┐
│                ESP32-S3 主控                     │
│  ┌─────────────────────────────────────────┐    │
│  │ WiFi + BLE + 外设接口                    │    │
│  └─────────────────────────────────────────┘    │
│       │           │           │                  │
│  ┌────┴────┐ ┌────┴────┐ ┌────┴────┐           │
│  │ 电机驱动│ │ 称重模块│ │ 语音模块│           │
│  │ TB6612  │ │ HX711   │ │ MAX98357│           │
│  └────┬────┘ └────┬────┘ └────┬────┘           │
│       │           │           │                  │
│  ┌────┴────┐ ┌────┴────┐ ┌────┴────┐           │
│  │ 直流电机│ │ 称重传感│ │ 喇叭    │           │
│  │ +螺旋杆 │ │ 器      │ │ +麦克风 │           │
│  └─────────┘ └─────────┘ └─────────┘           │
│                                                  │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐           │
│  │ 红外检测│ │ 温湿度  │ │ 摄像头  │           │
│  │ 缺粮    │ │ 传感器  │ │ OV2640  │           │
│  └─────────┘ └─────────┘ └─────────┘           │
└─────────────────────────────────────────────────┘

2.2 电机控制电路

c 复制代码
// TB6612电机驱动
#define MOTOR_IN1   GPIO_NUM_1
#define MOTOR_IN2   GPIO_NUM_2
#define MOTOR_PWM   GPIO_NUM_3

void motor_init(void) {
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << MOTOR_IN1) | (1ULL << MOTOR_IN2),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&io_conf);
    
    // PWM配置
    ledc_timer_config_t timer_conf = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .timer_num = LEDC_TIMER_0,
        .duty_resolution = LEDC_TIMER_10_BIT,
        .freq_hz = 1000,
        .clk_cfg = LEDC_AUTO_CLK
    };
    ledc_timer_config(&timer_conf);
    
    ledc_channel_config_t channel_conf = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = LEDC_CHANNEL_0,
        .timer_sel = LEDC_TIMER_0,
        .gpio_num = MOTOR_PWM,
        .duty = 0,
        .hpoint = 0
    };
    ledc_channel_config(&channel_conf);
}

void motor_set_speed(int speed) {
    // speed: -100 ~ 100
    if (speed > 0) {
        gpio_set_level(MOTOR_IN1, 1);
        gpio_set_level(MOTOR_IN2, 0);
    } else if (speed < 0) {
        gpio_set_level(MOTOR_IN1, 0);
        gpio_set_level(MOTOR_IN2, 1);
        speed = -speed;
    } else {
        gpio_set_level(MOTOR_IN1, 0);
        gpio_set_level(MOTOR_IN2, 0);
    }
    
    uint32_t duty = speed * 1023 / 100;
    ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
}

2.3 称重传感器

c 复制代码
// HX711称重模块
#define HX711_SCK   GPIO_NUM_4
#define HX711_DOUT  GPIO_NUM_5

typedef struct {
    float scale_factor;     // 比例系数
    long offset;            // 零点偏移
    float weight;           // 当前重量(g)
    float last_weight;      // 上次重量
} hx711_t;

void hx711_init(hx711_t *hx) {
    gpio_set_direction(HX711_SCK, GPIO_MODE_OUTPUT);
    gpio_set_direction(HX711_DOUT, GPIO_MODE_INPUT);
    hx->scale_factor = 1.0;
    hx->offset = 0;
}

long hx711_read_raw(void) {
    // 等待数据就绪
    while (gpio_get_level(HX711_DOUT) == 1) {
        vTaskDelay(1);
    }
    
    long data = 0;
    for (int i = 0; i < 24; i++) {
        gpio_set_level(HX711_SCK, 1);
        ets_delay_us(1);
        data = (data << 1) | gpio_get_level(HX711_DOUT);
        gpio_set_level(HX711_SCK, 0);
        ets_delay_us(1);
    }
    
    // 第25个脉冲设置增益
    gpio_set_level(HX711_SCK, 1);
    ets_delay_us(1);
    gpio_set_level(HX711_SCK, 0);
    
    // 转换为有符号数
    if (data & 0x800000) {
        data |= 0xFF000000;
    }
    
    return data;
}

float hx711_get_weight(hx711_t *hx, int times) {
    long sum = 0;
    for (int i = 0; i < times; i++) {
        sum += hx711_read_raw();
    }
    long avg = sum / times;
    
    hx->weight = (avg - hx->offset) / hx->scale_factor;
    return hx->weight;
}

void hx711_calibrate(hx711_t *hx, float known_weight) {
    // 1. 空载时记录零点
    printf("请移除所有物品...\n");
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    hx->offset = hx711_read_raw();
    printf("零点偏移: %ld\n", hx->offset);
    
    // 2. 放置已知重量物品
    printf("请放置 %.1fg 物品...\n", known_weight);
    vTaskDelay(3000 / portTICK_PERIOD_MS);
    long reading = hx711_read_raw();
    
    // 3. 计算比例系数
    hx->scale_factor = (reading - hx->offset) / known_weight;
    printf("比例系数: %.2f\n", hx->scale_factor);
}

三、定时投喂系统

3.1 定时任务管理

c 复制代码
typedef struct {
    uint8_t hour;
    uint8_t minute;
    uint8_t weekdays;      // 位掩码:bit0=周日, bit1=周一...
    float amount_g;         // 投喂量(克)
    bool enabled;
    char voice_msg[64];     // 语音消息
} feeding_schedule_t;

typedef struct {
    feeding_schedule_t schedules[MAX_SCHEDULES];
    int count;
    time_t last_feed_time;
    float daily_total;
} feeding_manager_t;

// 检查是否需要投喂
bool check_schedule(feeding_manager_t *mgr) {
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    
    for (int i = 0; i < mgr->count; i++) {
        feeding_schedule_t *s = &mgr->schedules[i];
        if (!s->enabled) continue;
        
        // 检查时间
        if (t->tm_hour != s->hour || t->tm_min != s->minute) continue;
        
        // 检查星期
        uint8_t weekday_bit = 1 << t->tm_wday;
        if (!(s->weekdays & weekday_bit)) continue;
        
        // 检查是否已投喂(防止重复)
        if (now - mgr->last_feed_time < 60) continue;
        
        // 执行投喂
        execute_feeding(s->amount_g, s->voice_msg);
        mgr->last_feed_time = now;
        mgr->daily_total += s->amount_g;
        
        return true;
    }
    return false;
}

// Cron表达式解析(高级版本)
typedef struct {
    uint8_t minute[60];     // 0-59
    uint8_t hour[24];       // 0-23
    uint8_t day_of_month[32]; // 1-31
    uint8_t month[12];      // 0-11
    uint8_t day_of_week[7]; // 0-6 (0=周日)
} cron_expr_t;

bool cron_match(cron_expr_t *cron, struct tm *t) {
    return cron->minute[t->tm_min] &&
           cron->hour[t->tm_hour] &&
           cron->day_of_month[t->tm_mday] &&
           cron->month[t->tm_mon] &&
           cron->day_of_week[t->tm_wday];
}

3.2 精准投喂控制

c 复制代码
typedef struct {
    float target_amount;    // 目标投喂量
    float current_amount;   // 当前已投喂
    float start_weight;     // 开始时食盆重量
    bool in_progress;       // 投喂进行中
    uint32_t start_time;    // 开始时间
    uint32_t timeout_ms;    // 超时时间
} feeding_process_t;

void execute_feeding(float amount_g, const char *voice_msg) {
    feeding_process_t process = {
        .target_amount = amount_g,
        .current_amount = 0,
        .start_weight = hx711_get_weight(&hx, 10),
        .in_progress = true,
        .start_time = get_timestamp(),
        .timeout_ms = 30000  // 30秒超时
    };
    
    // 播放语音
    if (voice_msg[0] != '\0') {
        play_voice(voice_msg);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    
    // 启动电机
    motor_set_speed(80);
    
    // 监控投喂量
    while (process.in_progress) {
        float current_weight = hx711_get_weight(&hx, 5);
        process.current_amount = current_weight - process.start_weight;
        
        // 达到目标量
        if (process.current_amount >= process.target_amount) {
            motor_set_speed(0);
            process.in_progress = false;
            break;
        }
        
        // 超时检测
        if (get_timestamp() - process.start_time > process.timeout_ms) {
            motor_set_speed(0);
            report_error(ERROR_FEEDING_TIMEOUT);
            process.in_progress = false;
            break;
        }
        
        // 卡粮检测
        if (detect_jam()) {
            motor_set_speed(-30);  // 反转
            vTaskDelay(500 / portTICK_PERIOD_MS);
            motor_set_speed(80);   // 重新正转
        }
        
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    
    // 记录投喂日志
    log_feeding(process.current_amount, process.start_time);
}

四、食物识别

4.1 摄像头方案

c 复制代码
// OV2640摄像头初始化
camera_config_t camera_config = {
    .pin_pwdn = CAM_PIN_PWDN,
    .pin_reset = CAM_PIN_RESET,
    .pin_xclk = CAM_PIN_XCLK,
    .pin_sccb_sda = CAM_PIN_SIOD,
    .pin_sccb_scl = CAM_PIN_SIOC,
    .pin_d7 = CAM_PIN_D7,
    .pin_d6 = CAM_PIN_D6,
    .pin_d5 = CAM_PIN_D5,
    .pin_d4 = CAM_PIN_D4,
    .pin_d3 = CAM_PIN_D3,
    .pin_d2 = CAM_PIN_D2,
    .pin_d1 = CAM_PIN_D1,
    .pin_d0 = CAM_PIN_D0,
    .pin_vsync = CAM_PIN_VSYNC,
    .pin_href = CAM_PIN_HREF,
    .pin_pclk = CAM_PIN_PCLK,
    .xclk_freq_hz = 20000000,
    .pixel_format = PIXFORMAT_JPEG,
    .frame_size = FRAMESIZE_QVGA,
    .jpeg_quality = 12,
    .fb_count = 2,
    .grab_mode = CAMERA_GRAB_LATEST
};

esp_err_t camera_init() {
    return esp_camera_init(&camera_config);
}

4.2 食物类型识别

python 复制代码
# 食物识别模型
class FoodTypeClassifier:
    def __init__(self, model_path):
        self.model = tflite.Interpreter(model_path)
        self.model.allocate_tensors()
        
        self.labels = ['dry_food', 'wet_food', 'treats', 'empty', 'unknown']
    
    def classify(self, image):
        # 预处理
        input_details = self.model.get_input_details()
        height, width = input_details[0]['shape'][1:3]
        
        resized = cv2.resize(image, (width, height))
        normalized = resized / 255.0
        input_data = np.expand_dims(normalized, axis=0).astype(np.float32)
        
        # 推理
        self.model.set_tensor(input_details[0]['index'], input_data)
        self.model.invoke()
        
        output_details = self.model.get_output_details()
        output = self.model.get_tensor(output_details[0]['index'])
        
        # 解析结果
        class_idx = np.argmax(output[0])
      
相关推荐
苏州邦恩精密1 小时前
浙江蔡司3D扫描仪应用领域及厂家选择分析
人工智能·科技·3d·自动化·制造
想会飞的蒲公英1 小时前
集成学习入门:Bagging、Boosting 到底在组合什么
人工智能·python·机器学习·集成学习·boosting
海外数字观察家1 小时前
品未云:博兹瓦纳华商批发零售一体化 ERP,破解本土软件适配难题|CSDN 技术分享
大数据·网络·人工智能·博兹瓦纳进销存系统·博兹瓦纳收银系统·博兹瓦纳erp系统·博兹瓦纳仓库管理系统
_老码1 小时前
AI-reader阅读助手开发过程
人工智能·python·ai
weixin_422329311 小时前
AgentScope Java ReActAgent 核心循环深度解析
java·开发语言·人工智能
SNKXD_11 小时前
2026年五款AI数字人系统效果差异:基于多维度横评的实证比较
大数据·人工智能
Lucky_5566881 小时前
山东捷瑞检测科技有限公司:政务信息化项目监理要点与收费标准解析
大数据·人工智能
2zcode1 小时前
低采样率ISAR成像的稀疏重建方法及其实时实现
图像处理·人工智能·计算机视觉
2501_930296991 小时前
驾驭大模型的对话艺术:深度拆解 OpenAI 官方 Prompt 指南与全场景实战心法
人工智能·prompt