给主子做了个小玩具

·  阅读 2635
给主子做了个小玩具

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!

背景

这是我们家的主子可爱粘人

IMG_4540.JPG

每天不是吃就是睡日子过的好不自在。

但是每当我想进步的时候它就会躺在我键盘上

IMG_4543.JPG

猫子果然是人类进步的绊脚石!

为了解决这个问题我决定给小猫咪做个下玩具可以让它来挤我键盘的时候让它自己玩去。

分析

小猫咪喜欢什么?

  1. 盒子 对盒子绝对是真爱有盒必进
  2. 好奇心 对一些声音很敏感,听到后会比较兴奋要去一探究竟
  3. 窗外的小鸟那也是真爱要是有小鸟那必须蹲着看
  4. 它平时还经常玩一些毛绒小球

还有就是它对任何玩具都只有一定的新鲜度,如果比较机械一般几天就不爱玩了 基于分析大致设计了这么一个玩具 在一个盒子里 放上一些毛绒小球,在盒子里开一些孔方便它用爪子伸进来抓取,同时盒子里面需要有一个发声装置比如可以播放小鸟的叫声,这声音可以更换,当它对当前声音不敏感后可以更换些新的声音,同时我们可以监听猫子的爪子伸入然后触发调大音量或者更尖锐的声音模拟出遭遇攻击😄

玩具的名字就叫 BirdBox

设计调研

盒子 先随便找个快递盒子随便开几个口子完成。

毛绒小球 刚好我有之前买的毛绒小球 ¸ IMG_4535_副本.jpg

放在一起

IMG_4536_副本.jpg

接下去是要开发的部分了 发声装置

我们可以使用一个mcu控制一个小喇叭来完成发声

硬件部分

esp8266 和小喇叭

v20.png

7ff7d7d9e9db4fddabe89537a599f4f6_tplv-k3u1fbpfcp-watermark.jpeg

采用github.com/earlephilho… 库即可播放声音 文档里用NPN三极管即可驱动,我这个带有8002B功放芯片也也没有问题

服务端

准备采用 Nestjs nestjs.com/

MQTT 服务器 emqx github.com/emqx/emqx

手机端

采用微信小程序开发

整体架构

设备端通过MQTT和云端保持通信,App端则通过HTTP和服务端保持通信 image.png

原型Demo开发

服务端实现

框架安装参考官方文档吧nestjs.com/

脚手架创建工程

nest new server

选用TypeOrm github.com/typeorm/typ… 作为数据库框架

app.module.ts 的 module中配置使用 sqlite 作为数据库,没多多少数据 sqlite 正合适~

TypeOrmModule.forRoot({
    type: 'sqlite',
    database: 'sqlite.db',
    autoLoadEntities: true,
    synchronize: true,
  })
复制代码

实现一个简单的curd 这里一个设备为例子

定义数据实体相当于表结构 device.entity.ts

import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Device {
    @PrimaryGeneratedColumn()
    id: number;

    @Column()
    name: string;

    @Column()
    serial: string;

    @Column()
    desc: string;
}

复制代码

然后在service 进行 curd 操作, 首先是在构造函数中注入 deviceRespository 然后使用它做相应的操作啦

@Injectable()
export class DeviceService {
    
  constructor(
    @InjectRepository(Device) private deviceRespository: Repository<Device>,
  ) {}


  create(createDeviceDto: CreateDeviceDto) {
    return this.deviceRespository.save(createDeviceDto);
  }


  findOne(id: number) {
    return this.deviceRespository.findOneBy({ id });
  }

  update(id: number, updateDeviceDto: UpdateDeviceDto) {
    return this.deviceRespository.update(id, updateDeviceDto);
  }

  remove(id: number) {
    // return this.deviceRespository.remove();
  }
}
复制代码

具体还是看官网吧

MQTT服务

基于 emqx 开源版本 github.com/emqx/emqx

直接 docker 部署服务

docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:latest
复制代码

服务端口部署在 1883, 控制台端口在 18083 默认账号 admin 默认密码 public

nestjs 连上 Mqtt 服务

安装mqtt module

npm install nest-mqtt mqtt --save
复制代码

app.module.ts 中配置好mqtt服务

 MqttModule.forRoot({
      host: 'localhost',
      port: 1883,
      queue: true,
    })
  ],
复制代码

监听和发布消息 在构造中注入 mqttService 可以用它完成publish操作,监听则可以使用 @Subscribe 装饰器完成

@Injectable()
export class AppService {

  constructor(@Inject(MqttService) private readonly mqttService: MqttService) {}
  getHello(): string {
    return 'Hello World!';
  }

  @Subscribe('test')
  test(@Payload() payload) {
    console.log("subscribe")
    console.log(payload)
  }

  publish() : string {
    this.mqttService.publish('play', {play: "on"});
    return 'publish'
  }
}
复制代码

至此我们已经可以实现通过发Http请求来触发一个mqtt消息了,也就可以实现通过手机端发送请求来达到控制设备端了

硬件

基于Arduino开发

配网

直接使用 WiFiManager github.com/tzapu/WiFiM… 即可完成配网,不过作为demo原型 直接暂时写死 ssid & password 即可

在setup 函数中

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
复制代码

MQTT 实现

基于 AsyncMqttClient github.com/marvinroger…


//初始化
void initMqtt(const char* clientId, OnMqttConnect connect, OnMqttMessage onMsg) {

    onConnect = connect;
    onMessage = onMsg;

    mqttClient.setClientId(clientId);
    mqttClient.onConnect(_onMqttConnect);
    mqttClient.onDisconnect(onMqttDisconnect);
    mqttClient.onSubscribe(onMqttSubscribe);
    mqttClient.onUnsubscribe(onMqttUnsubscribe);
    //注册消息回调
    mqttClient.onMessage(_onMqttMessage);
    mqttClient.onPublish(onMqttPublish);
    mqttClient.setServer(MQTT_HOST, PORT);
    mqttClient.setMaxTopicLength(512);
    mqttClient.setKeepAlive(60);
    mqttClient.connect();
}

// 收到消息

void _onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  Serial.print("  qos: ");
  Serial.println(properties.qos);
  Serial.print("  dup: ");
  Serial.println(properties.dup);
  Serial.print("  retain: ");
  Serial.println(properties.retain);
  Serial.print("  len: ");
  Serial.println(len);
  Serial.print("  index: ");
  Serial.println(index);
  Serial.print("  total: ");
  Serial.println(total);

  onMessage(topic, payload, properties, len, index, total);
}

//使用来注册监听
mqttClient.subscribe(topic)
复制代码

至此我们就可以让使用通过MQTT来控制 我们的模块啦

播放声音

首先是接线地和电源没什么好说的数据线要和RX接也就是D8边上的那个 如图接好~ IMG_4534_副本.jpg

根据github.com/earlephilho… 该库文档它不仅支持 SPIFFS 通过文件播放 还支持 http 流播放 这里我们暂时采用文件播放 后续考虑是否要切成用http流播放,直接根据它的样例代码即可实现音乐播放

  file = new AudioFileSourceSPIFFS("/bird.mp3");
  id3 = new AudioFileSourceID3(file);
  id3->RegisterMetadataCB(MDCallback, (void*)"ID3TAG");
  out = new AudioOutputI2SNoDAC();
  mp3 = new AudioGeneratorMP3();
  mp3->begin(id3, out);
复制代码

bird.mp3文件只要放到工程文件的data文件夹下上传时就会上传了

至此我们已经完成了所有基础功能。

测试

终于到了激动人心的测试环节,测试喵也已经准备好了,由于不能插入视频这里只能看看图片了,效果挺好!成功的引起了两个测试的好奇~

image.png

测试视频可以移步B站查看 www.bilibili.com/video/BV1wd…

后续

完善小程序功能可以选择声音列表,可以定时触发等功能

image.png

当前只有部分后端片段代码放在这里 github.com/6a209/birdb… 后续会更新上设备端和小程序端相关代码。

分类:
代码人生
标签:
收藏成功!
已添加到「」, 点击更改