草庐IT

懒人开关 ESP32控制舵机旋转(基于ESP32+SG90舵机+微信小程序)

小杰爱吃西瓜 2023-07-25 原文

提示:站在巨人肩膀上的小白,大家可以提出自己的看法。如有侵删;

原文参考链接:esp32单片机控制舵机 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/566948087

文章目录

目录

前言

一、准备步骤

二、使用步骤

1.ESP32和SG90舵机的连接

2.读入数据

3.外壳的打印

4.MQTT连接

若是纯小白,可以看一下这个

导入库和站看日志的方法,若找不到可以从官网上进行下载之后进行导入


前言

        随着智能化时代的到来,你是否想解放双手,实现家居智能化,这多酷啊!!懒人开关专属于你的定制。


有点模糊,但是实际功能实现啦!微信小程序端来自B站小林技术员的个人空间_哔哩哔哩_bilibili

大家可以私信一下;

 

一、准备步骤

  • 先准备一个SG90舵机;
  • 再来一个ESP32单片机;
  • 最后就是很多根杜邦线 ;
  • 安卓线来一条进行烧录的时候使用;

二、使用步骤

1.ESP32和SG90舵机的连接:

  1. 先来科普一下舵机的小知识:

        (1)舵机分三条线,分别是棕色:GND;红色:VCC (这里我们采用的是5V电压,力气更大一点个人理解哈);橘色线:脉冲输入(也就是信号线);

        (2)开始接线啦:棕色==GND 红色==自带的5V 橘色==GPIO13

 先上一个ESP32的引脚图,详细内容在图中都有标注,自行查看即可(图是从网上找到的,很详细!如有侵删)

        舵机转动角度与占空比的关系: 占 空 比 = ( 角 度 90 + 0.5 ) ∗ 1023 / 20 占空比=(\frac {角度}{90}+0.5)*1023/20占空比=( 90角度 +0.5)∗1023/20:

舵机的购买和详细知识在这里不做过过多的解释了,自行从参考链接中查询。

2.读入数据

整体就是判断1,0开关,接收到后返回OK;本文采用的是MQTT进行通信,当然后期你也可以自行添加蓝牙的通信方式等等;

代码如下:

int freq = 50;      // 1/50秒,50Hz的频率,20ms的周期,这个变量用来存储时钟基准。
int channel = 8;    // 通道(高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。)
int resolution = 8; // 分辨率设置为8,就是2的8次方,用256的数值来映射角度,看下方的占空比函数。
const int led = 13;

/*****将局部变量已改为全局变量(根据实际需求再自行调整)****/
int degree;
float deadZone = 0;
String push_msg = "OK";
//最好不要使用max、min...之类的词作为变量,容易被编译器识别成方法、类、函数...
float maxs = 32;//对应2.5ms(2.5ms/(20ms/256))
/*****************************/

WiFiClient espClient;  // 定义WLAN实例
PubSubClient client(espClient);  // 定义PubSubClient的实例
 
/*****将int degree改为 int c,通过赋值修改degree的值******/
/*****由于该函数中return一个int类型数据,所以应将函数的返回值类型void改为int******/
int calculatePWM(int c) //定义函数用于输出PWM的占空比
{ //0-180度
  degree = c;
/*****************************************************/

 //20ms周期内,高电平持续时长0.5-2.5ms,对应0-180度舵机角度,参考上面的180度对应图。
   deadZone = 6.4;//对应0.5ms(0.5ms/(20ms/256))
  
  if (degree < 0)
    degree = 0;
  if (degree > 200)
    degree = 180;
  return (int)(((maxs - deadZone) / 180) * degree + deadZone); //返回度数对应的高电平的数值
}

定义两个主题用于发送和接受;

/*****由于该函数中return一个int类型数据,所以应将函数的返回值类型void改为int******/
int leddev(char* topic, byte* payload, unsigned int length)
/*************************************************************************/

{
  String msg="";
  for (int i = 0; i < length; i++) {
    msg+= (char)payload[i];
  }
  Serial.println(msg);
  if (msg == "1")
  {
    degree = 0;
    ledcWrite(channel, calculatePWM(180)); // 输出PWM,设置 LEDC 通道的占空比。
    
    client.publish(Mqtt_pub_topic,push_msg.c_str());
    
    return (int)(((maxs - deadZone) / 180) * degree + deadZone); //返回度数对应的高电平的数值
  }
  else
  {
    Serial.printf("ok");
     client.publish(Mqtt_pub_topic,push_msg.c_str());
     ledcWrite(channel, calculatePWM(90)); // 输出PWM,设置 LEDC 通道的占空比。
  }
}

来一个标志位;

标志位:拿着钥匙进来返回OK 

int flag = 0;
void loop()
{
  
  if (!client.connected()) //如果MQTT服务器连接不成功,则反复重试,连接成功后重新订阅。
  {
    reconnect();
  }
  client.loop();
  if(flag==0){
    client.publish(Mqtt_pub_topic,push_msg.c_str());
    flag=1;
    Serial.println("发送ok!");
   }

看一下端口 

3.外壳的打印

外壳的打印使用的是solidworks,其中有很多偏差就自行又添加了一些小组件,后期可能会发布一下完成版的外壳源码。

4.MQTT连接

1、先创建一下你的项目

2、设置两个主题来进行接受和发送,便于自行检查;

arduino部分的全部代码附上:

代码汇中的注释部分已经过分详细了,请自行查看即可;

#include <WiFi.h>
#include <PubSubClient.h>//发布订阅库,也可以使用mqtt.h
#include <Arduino.h>
//连接mqtt
const char* ssid = "  "; //WIFI的ID
const char* password = "  "; //WIFI的PASSWORD
const char* mqtt_server = "  "; // mqtt服务器的地址。
const char* TOPIC = "set"; // 订阅信息主题
const char* Mqtt_pub_topic = "get"; // 订阅信息主题
const char* client_id = "esp32";//设备的客户端编号
char* sh = new char[10]; //定义两个字符串数组,用来存放温湿度的浮点数转换过来的字符串。
char* st = new char[10];
long lastMsg = 0;     // 记录上一次发送信息的时间。

int freq = 50;      // 1/50秒,50Hz的频率,20ms的周期,这个变量用来存储时钟基准。
int channel = 8;    // 通道(高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。)
int resolution = 8; // 分辨率设置为8,就是2的8次方,用256的数值来映射角度,看下方的占空比函数。
const int led = 13;

/*****将局部变量已改为全局变量(根据实际需求再自行调整)****/
int degree;
float deadZone = 0;
String push_msg = "OK";
//最好不要使用max、min...之类的词作为变量,容易被编译器识别成方法、类、函数...
float maxs = 32;//对应2.5ms(2.5ms/(20ms/256))
/*****************************/

WiFiClient espClient;  // 定义WLAN实例
PubSubClient client(espClient);  // 定义PubSubClient的实例
 
/*****将int degree改为 int c,通过赋值修改degree的值******/
/*****由于该函数中return一个int类型数据,所以应将函数的返回值类型void改为int******/
int calculatePWM(int c) //定义函数用于输出PWM的占空比
{ //0-180度
  degree = c;
/*****************************************************/

 //20ms周期内,高电平持续时长0.5-2.5ms,对应0-180度舵机角度,参考上面的180度对应图。
   deadZone = 6.4;//对应0.5ms(0.5ms/(20ms/256))
  
  if (degree < 0)
    degree = 0;
  if (degree > 200)
    degree = 180;
  return (int)(((maxs - deadZone) / 180) * degree + deadZone); //返回度数对应的高电平的数值
}

void setup()
{
  Serial.begin(9600);
  ledcSetup(channel, freq, resolution); // 用于设置 LEDC 通道的频率和分辨率。
  ledcAttachPin(led, channel);          // 将通道与对应的引脚连接
  //
  WiFi.begin(ssid, password);
   while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
  }
  client.setServer(mqtt_server, 1883);//设定MQTT服务器与使用的端口
  client.setCallback(leddev); //设定回调程序,当ESP32收到订阅消息时会调用此方法
  
  delay(5000);
  
  client.publish(Mqtt_pub_topic,push_msg.c_str());
  Serial.println(push_msg);
}

/*****由于该函数中return一个int类型数据,所以应将函数的返回值类型void改为int******/
int leddev(char* topic, byte* payload, unsigned int length)
/*************************************************************************/

{
  String msg="";
  for (int i = 0; i < length; i++) {
    msg+= (char)payload[i];
  }
  Serial.println(msg);
  if (msg == "1")
  {
    degree = 0;
    ledcWrite(channel, calculatePWM(180)); // 输出PWM,设置 LEDC 通道的占空比。
    
    client.publish(Mqtt_pub_topic,push_msg.c_str());
    
    return (int)(((maxs - deadZone) / 180) * degree + deadZone); //返回度数对应的高电平的数值
  }
  else
  {
    Serial.printf("ok");
     client.publish(Mqtt_pub_topic,push_msg.c_str());
     ledcWrite(channel, calculatePWM(90)); // 输出PWM,设置 LEDC 通道的占空比。
  }
}

void reconnect() {
  while (!client.connected()) {
    if (client.connect(client_id))
    {
      client.subscribe(TOPIC);
    }
    else
    {
      delay(5000);
    }
  }
}
int flag = 0;
void loop()
{
  
  if (!client.connected()) //如果MQTT服务器连接不成功,则反复重试,连接成功后重新订阅。
  {
    reconnect();
  }
  client.loop();
  if(flag==0){
    client.publish(Mqtt_pub_topic,push_msg.c_str());
    flag=1;
    Serial.println("发送ok!");
   }
//  for (int d = 0; d <= 180; d += 10)
//  {
//    ledcWrite(channel, calculatePWM(d)); // 输出PWM,设置 LEDC 通道的占空比。
//    Serial.printf("value=%d,calcu=%d\n", d, calculatePWM(d));
//    delay(1000);
//  }  
}

   以上就是今天要讲的内容,本文仅仅简单介绍了MQTT通讯连接的使用和舵机旋转控制方式;


若是纯小白,可以看一下这个哈

导入库和站看日志的方法,若找不到可以从官网上进行下载之后进行导入;

(1)导入ESP32的库这里是获取芯片的ID为例子:

 (2)打开串口监视器就可以看到,ESP32输出的日志;

 ​​​​​

有关懒人开关 ESP32控制舵机旋转(基于ESP32+SG90舵机+微信小程序)的更多相关文章

  1. 叮咚买菜基于 Apache Doris 统一 OLAP 引擎的应用实践 - 2

    导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵

  2. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  5. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  6. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

  7. ruby - 在 Rakefile 中动态生成 Rake 测试任务(基于现有的测试文件) - 2

    我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n

  8. ruby - 如何使用 Ruby 基于字母数字字符串生成颜色? - 2

    我想要像“嘿那里”这样的东西变成,例如,#316583。我希望将任意长度的字符串“归结”为十六进制颜色。我不知道从哪里开始。我在想,每个字符串的MD5散列都是不同的-但如何将该散列转换为十六进制颜色数字? 最佳答案 你可以只取几位前几位:require'digest/md5'color=Digest::MD5.hexdigest('Mytext')[0..5] 关于ruby-如何使用Ruby基于字母数字字符串生成颜色?,我们在StackOverflow上找到一个类似的问题:

  9. 【自动驾驶环境感知项目】——基于Paddle3D的点云障碍物检测 - 2

    文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3

  10. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

随机推荐