利用开源小智AI制作桌宠机器狗指南

一.源码下载与准备

访问小智AI的官方源码下载地址,获取最新版本的源码。下载完成后,使用Visual Studio Code(VS Code)打开项目。为了确保项目能够顺利编译和运行,需要在VS Code中安装ESP-IDF开发环境。具体安装步骤可参考官方文档或相关教程。

二.源码修改与功能实现

1.编写代码

在项目目录main/iot/things下,新建一个名为dog.cc的文件。该文件将用于实现机器狗的四个舵机的核心控制逻辑。以下是示例代码,供参考:

#include "iot/thing.h"
#include "board.h"
#include "audio_codec.h"
#include <driver/gpio.h>
#include <esp_log.h>

#include "freertos/task.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "driver/mcpwm.h"

#define TAG "Dog"

#define SERVO_FREQ 50        // 50Hz,适用于 SG90 舵机
#define MIN_PULSE_WIDTH 500  // 最小脉宽 (500us) 对应 0° 位置
#define MAX_PULSE_WIDTH 2500 // 最大脉宽 (2500us) 对应 180° 位置
#define DEGREE_TO_PULSE(degree) (MIN_PULSE_WIDTH + (MAX_PULSE_WIDTH - MIN_PULSE_WIDTH) * degree / 180)

#define SERVO_GPIO_1 GPIO_NUM_17 //(gpio_num_t)17   GPIO for servo 1 LF  左前
#define SERVO_GPIO_2 GPIO_NUM_14 //(gpio_num_t)14   GPIO for servo 2 RF  右前
#define SERVO_GPIO_3 GPIO_NUM_18 //(gpio_num_t)18   GPIO for servo 3 LB  左后
#define SERVO_GPIO_4 GPIO_NUM_13 //(gpio_num_t)13   GPIO for servo 4 RB  右后

namespace iot
{
    int dog_state_ = 0;
    int waitTime = 200;
    void set_servo_angle(mcpwm_unit_t mcpwm_num, mcpwm_timer_t timer_num, int gpio_num, int angle)
    {
        uint32_t pulse_width = DEGREE_TO_PULSE(angle); // 将角度转化为脉宽

        // 设置指定通道的占空比
        if (mcpwm_num == MCPWM_UNIT_0)
        {
            if (gpio_num == SERVO_GPIO_1)
            {
                mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_A, (pulse_width / 20000.0) * 100); // 计算占空比
            }
            else if (gpio_num == SERVO_GPIO_2)
            {
                mcpwm_set_duty(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_GEN_B, (pulse_width / 20000.0) * 100);
            }
        }
        else if (mcpwm_num == MCPWM_UNIT_1)
        {
            if (gpio_num == SERVO_GPIO_3)
            {
                mcpwm_set_duty(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_GEN_A, (pulse_width / 20000.0) * 100);
            }
            else if (gpio_num == SERVO_GPIO_4)
            {
                mcpwm_set_duty(MCPWM_UNIT_1, MCPWM_TIMER_1, MCPWM_GEN_B, (pulse_width / 20000.0) * 100);
            }
        }
        vTaskDelay(50 / portTICK_PERIOD_MS);
        // 更新占空比
        mcpwm_sync_disable(MCPWM_UNIT_0, MCPWM_TIMER_0);
        mcpwm_sync_disable(MCPWM_UNIT_1, MCPWM_TIMER_1);
    }

     // 站立
    void zhanli()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }

    // 前进
    void qianjin()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);  // 舵机 1 到 90 度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 135); // 舵机 2 到 135度
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 45);  // 舵机 3 到 45 度
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);  // 舵机 4 到 90 度
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 135);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 45);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 45);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 135);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }

    // 后退
    void houtui()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 45);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 135);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 135);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 45);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }

    // 左转
    void zuozhuan()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 45);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 45);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 135);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 135);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }

    // 右转
    void youzhuan()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 45);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 135);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 135);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 45);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 45);
        vTaskDelay(pdMS_TO_TICKS(waitTime));

        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 135);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }

    // 趴下
    void paxia()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 25);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 155);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 25);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 155);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }

    // 蹲下
    void dunxia()
    {
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 25);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 155);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
    }
    //点头
    void diantou()
    {   
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 45);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 155);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 90);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 45);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 155);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        dog_state_ = 0;
    }
    //打招呼
    void baishou()
    {   
        // 控制四个舵机分别到不同角度
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_1, 90);
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 165);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_3, 25);
        set_servo_angle(MCPWM_UNIT_1, MCPWM_TIMER_1, SERVO_GPIO_4, 155);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 165);
        vTaskDelay(pdMS_TO_TICKS(waitTime));
        set_servo_angle(MCPWM_UNIT_0, MCPWM_TIMER_0, SERVO_GPIO_2, 90);
        dog_state_ = 0;
    }

    void task1()
    {
        while (1)
        {
            switch (dog_state_) {
                case 0: zhanli();    break;
                case 1: qianjin();   break;
                case 2: houtui();    break;
                case 3: zuozhuan();  break;
                case 4: youzhuan();  break;
                case 5: paxia();     break;
                case 6: dunxia();    break;
                case 7: diantou();   break;
                case 8: baishou();   break;
                default: break;      // 默认处理
            }
        }
    }

    class Dog : public Thing
    {
    private:
        void InitializeGpio()
        {
            // 初始化4个舵机的PWM
            const gpio_num_t servo_pins[4] = {SERVO_GPIO_1, SERVO_GPIO_2, SERVO_GPIO_3, SERVO_GPIO_4};

            for (int i = 0; i < 4; i++)
            {
                mcpwm_gpio_init(MCPWM_UNIT_0, static_cast<mcpwm_io_signals_t>(MCPWM0A + i), servo_pins[i]);
            }

            mcpwm_config_t pwm_config = {
                .frequency = 50, // 舵机标准50Hz
                .cmpr_a = 0,
                .cmpr_b = 0,
                .duty_mode = MCPWM_DUTY_MODE_0,
                .counter_mode = MCPWM_UP_COUNTER};
            mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);

            // 创建任务
            xTaskCreate([](void *arg)
                        {
            task1();
            vTaskDelete(NULL); }, "dogControl", 4096 * 4, this, 1, nullptr);
        }

    public:
        Dog() : Thing("Dog", "A test Dog")
        {
            InitializeGpio();

            // 定义设备的属性
            properties_.AddBooleanProperty("dog_forward", "小狗是否前进", [this]() -> bool
                                           { return dog_state_ == 1; });
            properties_.AddBooleanProperty("dog_back", "小狗是否后退", [this]() -> bool
                                           { return dog_state_ == 2; });
            properties_.AddBooleanProperty("dog_left", "小狗是否左转", [this]() -> bool
                                           { return dog_state_ == 3; });
            properties_.AddBooleanProperty("dog_right", "小狗是否右转", [this]() -> bool
                                           { return dog_state_ == 4; });
            properties_.AddBooleanProperty("dog_pa", "小狗是否趴下", [this]() -> bool
                                           { return dog_state_ == 5; });
            properties_.AddBooleanProperty("dog_dun", "小狗是否蹲下", [this]() -> bool
                                           { return dog_state_ == 6; });
            properties_.AddBooleanProperty("dog_dian", "小狗是否点头", [this]() -> bool
                                           { return dog_state_ == 7; });
            properties_.AddBooleanProperty("dog_zhao", "小狗是否打招呼", [this]() -> bool
                                           { return dog_state_ == 8; });
            properties_.AddBooleanProperty("dog_stop", "小狗是否站立", [this]() -> bool
                                           { return dog_state_ == 0; });

            // 定义设备可以被远程执行的指令
            methods_.AddMethod("DogGoForward", "小狗前进", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 1; });
            methods_.AddMethod("DogGoBack", "小狗后退", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 2; });
            methods_.AddMethod("DogGoLeft", "小狗左转", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 3; });
            methods_.AddMethod("DogGoRight", "小狗右转", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 4; });
            methods_.AddMethod("DogGoPa", "小狗趴下", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 5; });
            methods_.AddMethod("DogGoDun", "小狗蹲下", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 6; });
            methods_.AddMethod("DogGoDian", "小狗点头", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 7; });
            methods_.AddMethod("DogGoZhao", "小狗打招呼", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 8; });
            methods_.AddMethod("DogGoStop", "小狗站立", ParameterList(), [this](const ParameterList &parameters)
                               { dog_state_ = 0; });
        }
    };
}

DECLARE_THING(Dog);
2.修改配置文件

在“main/boards/bread-compact-wifi-lcd/compact_wifi_board.cc”文件(我的是1.54彩屏,如果是0.96或1.3寸屏幕sd1306驱动的屏幕,请修改main/boards/bread-compact-wifi/compact_wifi_board.cc文件)中的InitializeIot方法,添加小狗控制代码

 thing_manager.AddThing(iot::CreateThing("Dog"));

三.编译与运行

完成代码编写后,使用ESP-IDF工具链进行编译。确保所有依赖项已正确安装,并按照项目结构进行配置。编译成功后,将生成的固件烧录到目标设备上,即可启动桌宠机器狗。

四.功能扩展与优化

根据实际需求,可以进一步扩展机器狗的功能。例如,添加语音识别模块、传感器控制或远程控制功能。通过不断优化代码和硬件配置,打造一个更加智能和互动的桌宠机器狗。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值