物联网之ESP32控制舵机、通过网页设置舵机角度、Web服务、舵机原理、接线、Arduino、WiFi、Http

news2024/12/28 22:32:27

MENU

  • 前言
  • 原理
  • 硬件电路设计
  • 软件程序设计
    • LEDC输出PWM信号
    • 使用第三方库控制舵机
    • 网页控制舵机


前言

舵机在电子产品中非常常见,比如四足机器人、固定翼航模等都有应用,因此学习舵机对电子制作非常有意义。本文章使用Arguino的PWM对SG90舵机旋转角度控制。


原理

舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。舵机只是一种通俗的叫法,其本质是一个伺服电机。

舵机

舵机有很多规格,但所有的舵机都有外接三根线,分别用棕、红和橙三种颜色进行区分,由于舵机品牌不同,颜色也会有所差异,棕色为接地线,红色为电源正极线,橙色为信号线。只要通过信号线给予规定的控制信号即可实现舵机码盘的转动。

接线

SG90的主要电气参数
使用电压: 4.8V~6V
尺寸: 221.5mm x 11.8mm x 22.7mm
重量: 9g
角度范围: 0-180°


舵机的工作原理是由接收机或者单片机发出信号给舵机,其内部有一个基准电路,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。经由电路板上的IC判断转动方向,再驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回信号,判断是否已经到达定位。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。一般舵机旋转的角度范围是0度到180度,当然也有0度到360度。


没有必要了解舵机的内部结构,只需要知道如何通过PWM控制其转动即可。舵机的控制就是通过一个固定的频率,给其不同的占空比的,来控制舵机不同的转角。


舵机的转动的角度是通过调节PWM(脉冲宽度调制)信号的占空比来实现的,标准PWM(脉冲宽度调制)信号的周期固定为20ms(50Hz),理论上脉宽分布应在1ms到2ms之间,但是,事实上脉宽可由0.5ms到2.5ms之间,脉宽和舵机的转角0°~180°相对应。有一点值得注意的地方,由于舵机牌子不同,对于同一信号,不同牌子的舵机旋转的角度也会有所不同。

角度与时间

0.5~2.5ms的PWM高电平部分对应控制180度舵机的0~180度,对应的控制关系。

对应关系

高电平占整个周期(20ms)的时间舵机旋转的角度对应的占空比
0.5ms0.5//20
1ms45°1//20
1.5ms90°1.5//20
2ms135°2//20
2.5ms180°2.5//20

硬件电路设计

材料名称数量
舵机1
杜邦线(跳线)3

线路图

注意接线顺序。


软件程序设计

LEDC输出PWM信号

首先,使用LEDC输出PWM信号,根据之前的实验原理,可以确定频率、最大脉宽与最小脉宽。

// 1/20秒,50Hz的频率,20ms的周期,这个变量用来存储时钟基准
#define FREQ 50
// 通道
// 高速通道(0~7)由80MHz时钟驱动
// 低速通道(8~15)由1MHz时钟驱动
#define CHANNEL 0
// 分辨率设置为8,就是2的8次方,用256的数值来映射角度
#define RESOLUTION 8
// 定义舵机PWM控制引脚
#define SERVO 13

// 定义函数用于输出PWM的占空比
int calculatePWM(int degree) {
  // 20ms周期内,高电平持续时长0.5-2.5ms,对应0-180度舵机角度
  // 对应0.5ms(0.5ms/(20ms/256))
  float min_width = 0.6 / 20 * pow(2, RESOLUTION);
  // 对应2.5ms(2.5ms/(20ms/256))
  float max_width = 2.5 / 20 * pow(2, RESOLUTION);
  if (degree < 0) degree = 0;
  if (degree > 180) degree = 180;
  // 返回度数对应的高电平的数值
  return (int)(((max_width - min_width) / 180) * degree + min_width);
}

void setup() {
  // 用于设置LEDC通道的频率和分辨率
  ledcSetup(CHANNEL, FREQ, RESOLUTION);
  // 将通道与对应的引脚连接
  ledcAttachPin(SERVO, CHANNEL);
}

void loop() {
  for (int i = 0; i <= 180; i += 10) {
    // 输出PWM,设置LEDC通道的占空比
    ledcWrite(CHANNEL, calculatePWM(i));
    delay(1000);
  }
}

使用第三方库控制舵机

如果想使用Arduino控制舵机就需要在ESP32Servo库,点击项目,选择加载库中的管理库

管理库

然后输入ESP32Servo,点击安装即可。

安装

可以在VSCode的PlatformIO中,根据案例了解ESP32Servo库的使用方法。

VSCode

#include <ESP32Servo.h>

#define SERVO_PIN 13
#define MAX_WIDTH 2500
#define MIN_WIDTH 500

// 定义servo对象
Servo my_servo;

void setup() {
  // 分配硬件定时器
  ESP32PWM::allocateTimer(0);
  // 设置频率
  my_servo.setPeriodHertz(50);
  // 关联servo对象与GPIO引脚,设置脉宽范围
  my_servo.attach(SERVO_PIN, MIN_WIDTH, MAX_WIDTH);
}

void loop() {
  my_servo.write(180);
  delay(1000);

  my_servo.write(0);
  delay(1000);
}

网页控制舵机

代码

#include <WiFi.h>
#include <WebServer.h>
#include <math.h>

// Wi-Fi 网络名称和密码
const char* ssid = "ShiLai";
const char* password = "MJgn20240904$";

// Web服务器对象
WebServer server(80);

// 频率、通道、分辨率和舵机引脚定义
#define FREQ 50
#define CHANNEL 0
#define RESOLUTION 8
#define SERVO 13

// 定义函数用于输出PWM的占空比
int calculatePWM(int degree) {
  // 20ms周期内,高电平持续时长0.5-2.5ms,对应0-180度舵机角度。
  float min_width = 0.6 / 20 * pow(2, RESOLUTION);
  float max_width = 2.5 / 20 * pow(2, RESOLUTION);
  if (degree < 0) degree = 0;
  if (degree > 180) degree = 180;
  return (int)(((max_width - min_width) / 180) * degree + min_width);
}

void setup() {
  // 设置串口波特率
  Serial.begin(9600);
  // 连接到Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("加载中...");
  }
  Serial.print("\nIP地址:");
  Serial.println(WiFi.localIP());
  // 用于设置 LEDC 通道的频率和分辨率
  ledcSetup(CHANNEL, FREQ, RESOLUTION);
  // 将通道与对应的引脚连接
  ledcAttachPin(SERVO, CHANNEL);
  // 设置处理网页请求的函数
  server.on("/", handleRoot);
  server.on("/set", handleServo);

  // 启动Web服务器
  server.begin();
}

void loop() {
  // 处理网页请求
  server.handleClient();
}

// 处理根页面的请求
void handleRoot() {
  String html = "<!DOCTYPE html>";
  html += "<html lang='en'>";
  html += "<head>";
  html += "<meta charset='UTF-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
  html += "<title>网页控制舵机</title>";
  html += "</head>";
  html += "<body>";
  html += "<h1>网页控制舵机</h1>";
  html += "<input id='idInpu' type='number' min='0' max='180' value='0' />";
  html += "<button style='margin-left: 8px;' οnclick='handleSetAngle()'>设置角度</button>";
  html += "<p id='idP'></p>";
  html += "<script>";
  html += "let idP = document.getElementById('idP');";
  html += "handleSetAngle();";
  html += "function handleSetAngle() {";
  html += "let idInpu = document.getElementById('idInpu').value;";
  html += "let xhttp = new XMLHttpRequest();";
  html += "idP.innerHTML = idInpu;";
  html += "xhttp.open('GET', '/set?angle=' + idInpu, true);";
  html += "xhttp.onreadystatechange = function() {";
  html += "let isCode = this.readyState === 4 && this.status === 200;";
  html += "if (isCode) idP.innerHTML = this.responseText;";
  html += "};";
  html += "xhttp.send();";
  html += "}";
  html += "</script>";
  html += "</body>";
  html += "</html>";
  server.send(200, "text/html", html);
}

// 处理舵机角度设置的请求
void handleServo() {
  String angleStr = server.arg("angle");
  int angle = angleStr.toInt();

  // 检查角度是否在0到180度之间
  if (angle >= 0 && angle <= 180) {
    ledcWrite(CHANNEL, calculatePWM(angle));
    server.send(200, "text/html", "Angle set to: " + angleStr);
  } else {
    server.send(200, "text/html", "Invalid angle. Please enter a value between 0 and 180.");
  }
}

解析
代码段使用ESP32通过Wi-Fi建立一个Web服务器,允许用户通过网页输入角度来控制舵机的旋转角度。


01、引入库和定义常量

#include <WiFi.h>
#include <WebServer.h>
#include <math.h>

WiFi.h用于连接Wi-Fi网络。
WebServer.h用于创建一个HTTP Web服务器。
math.h包含数学函数库,用于进行角度与PWM信号的计算。


02、Wi-Fi 网络名称和密码

const char* ssid = "ShiLai";
const char* password = "MJgn20240904$";

ssid和password定义需要连接的Wi-Fi网络的名称和密码。


03、Web服务器对象

WebServer server(80);

创建一个WebServer对象,端口号为80,表示HTTP服务器的默认端口。


04、舵机控制的定义

#define FREQ 50
#define CHANNEL 0
#define RESOLUTION 8
#define SERVO 13

FREQ: PWM信号的频率设置为50Hz(标准舵机的工作频率)。
CHANNEL: LEDC通道编号,ESP32上使用硬件PWM控制舵机。
RESOLUTION: PWM信号的分辨率设置为8位。
SERVO: 舵机信号线连接的引脚编号为13。


05、定义函数用于输出PWM的占空比

int calculatePWM(int degree) {
  float min_width = 0.6 / 20 * pow(2, RESOLUTION);
  float max_width = 2.5 / 20 * pow(2, RESOLUTION);
  if (degree < 0) degree = 0;
  if (degree > 180) degree = 180;
  return (int)(((max_width - min_width) / 180) * degree + min_width);
}

calculatePWM函数用于将舵机的角度(0~180度)转换为对应的PWM占空比。
min_width和max_width分别表示对应于0度和180度时的PWM占空比宽度。
通过线性插值计算出给定角度对应的PWM信号。


06、setup函数

void setup() {
  Serial.begin(9600);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("加载中...");
  }
  Serial.print("\nIP地址:");
  Serial.println(WiFi.localIP());
  ledcSetup(CHANNEL, FREQ, RESOLUTION);
  ledcAttachPin(SERVO, CHANNEL);
  server.on("/", handleRoot);
  server.on("/set", handleServo);
  server.begin();
}

Serial.begin(9600)初始化串口通信,波特率为9600,用于调试信息输出。
WiFi.begin(ssid, password)尝试连接Wi-Fi网络,等待连接成功。
ledcSetup(CHANNEL, FREQ, RESOLUTION)配置LEDC通道,设置PWM频率和分辨率。
ledcAttachPin(SERVO, CHANNEL)将LEDC通道与舵机信号引脚连接。
server.on("/", handleRoot)设置根路径的HTTP请求处理函数。
server.on("/set", handleServo)设置用于调整舵机角度的HTTP请求处理函数。
server.begin()启动Web服务器。


07、loop函数

void loop() {
  server.handleClient();
}

loop函数中调用server.handleClient(),用于不断处理来自客户端的HTTP请求。


08、处理根页面的请求

void handleRoot() {
  String html = "<!DOCTYPE html>...";
  server.send(200, "text/html", html);
}

handleRoot函数生成一个HTML页面,用户可以在该页面中输入舵机角度,并通过点击按钮发送请求以设置舵机角度。
server.send(200, “text/html”, html)向客户端发送HTML内容。


09、处理舵机角度设置的请求

void handleServo() {
  String angleStr = server.arg("angle");
  int angle = angleStr.toInt();

  if (angle >= 0 && angle <= 180) {
    ledcWrite(CHANNEL, calculatePWM(angle));
    server.send(200, "text/html", "Angle set to: " + angleStr);
  } else {
    server.send(200, "text/html", "Invalid angle. Please enter a value between 0 and 180.");
  }
}

handleServo函数接收HTTP请求中的angle参数,并将其转换为整数。
检查角度是否在0到180度之间,若在范围内则调用ledcWrite函数设置舵机的PWM信号,否则返回错误信息。


10、总结
代码段在ESP32上实现一个Web服务器,允许用户通过网页界面输入舵机的角度,服务器接收到请求后将角度转换为PWM信号以控制舵机旋转。


效果图

0度

0°


90度

90°


180度

180°

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2109209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是Hash冲突?如何解决Hash冲突?

目录 一丶什么是Hash冲突 二丶如何解决Hash冲突 简介&#xff1a;Hash叫做‘散列表’&#xff0c;就是把任意长度输入&#xff0c;通过散列算法&#xff0c;变成固定长度输出&#xff0c;该输出结果是散列值。其实这种转换是一种压缩映射&#xff0c;散列表的空间通常小于输入…

深入解析EF Core并发控制:乐观与悲观策略的全面对比与实战应用

1. 前言 在使用EF Core开发应用程序时&#xff0c;并发控制是确保数据一致性的重要机制。EF Core 提供了两种主要的并发控制策略&#xff1a;乐观并发控制和悲观并发控制。它们各自有不同的应用场景和实现方式。本文将详细介绍这两种并发控制的区别、常见的应用场景&#xff0…

fastadmin 文件上传七牛云

1-安装七牛云官方SDK composer require qiniu/php-sdk 2-七牛云配置 <?phpnamespace app\common\controller;use Qiniu\Storage\BucketManager; use think\Config; use Qiniu\Auth; use Qiniu\Storage\UploadManager; use think\Controller; use think\Db;/*** 七牛基类*…

python操作kafka

一、参考阿里云的官方链接&#xff1a; 使用Python SDK接入Kafka收发消息_云消息队列 Kafka 版(Kafka)-阿里云帮助中心 二、安装python环境 三、添加python依赖库 pip install confluent-kafka1.9.2 四、新建一个setting.py文件配置信息 kafka_setting {sasl_plain_user…

爆改YOLOv8|利用SCConv改进yolov8-即轻量又涨点

1&#xff0c;本文介绍 SCConv&#xff08;空间和通道重构卷积&#xff09;是一种高效的卷积模块&#xff0c;旨在优化卷积神经网络&#xff08;CNN&#xff09;的性能&#xff0c;通过减少空间和通道的冗余来降低计算资源的消耗。该模块由两个核心组件构成&#xff1a; 空间重…

斯坦福UE4 C++课学习补充25:寻路EQS

文章目录 一、创建EQS二、修改行为树三、查询上下文 一、创建EQS 场景查询系统EQS&#xff1a;可用于收集场景相关的数据。然后该系统可以使用生成器&#xff0c;通过各种用户定义的测试就这些数据提问&#xff0c;返回符合所提问题类型的最佳项目Item。 EQS的一些使用范例包…

Unity【Colliders碰撞器】和【Rigibody刚体】的应用——小球反弹效果

目录 Collider 2D 定义&#xff1a; 类型&#xff1a; Rigidbody 2D 定义&#xff1a; 属性和行为&#xff1a; 运动控制&#xff1a; 碰撞检测&#xff1a; 结合使用 实用检测 延伸拓展 1、在Unity中优化Collider 2D和Rigidbody 2D的性能 2、Unity中Collider 2D…

香橙派列出附近所有的WiFi

使用 nmcli nmcli 是 NetworkManager 的命令行工具&#xff0c;它可以用来检索和管理网络连接。 nmcli device wifi list这个命令会列出所有周围的WiFi网络。

社区电商系统源码之卷轴模式:商业模式分析

随着互联网技术的发展&#xff0c;电商平台的竞争日益激烈&#xff0c;如何留住用户并提升用户粘性成为了各大电商平台关注的重点。卷轴模式作为一种新兴的用户参与和激励机制&#xff0c;在社区电商系统中得到了广泛的应用。本文将从技术角度探讨卷轴模式在社区电商系统中的实…

rust 命令行工具rsup管理前端npm依赖

学习了一年的 rust 了&#xff0c;但是不知道用来做些什么&#xff0c;也没能赋能到工作中&#xff0c;现在前端基建都已经开始全面进入 rust 领域了&#xff0c;rust 的前端生态是越来越好。但是自己奈何水平不够&#xff0c;想贡献点什么&#xff0c;无从下手。 遂想自己捣鼓…

Leetcode3256. 放三个车的价值之和最大 I

Every day a Leetcode 题目来源&#xff1a;3256. 放三个车的价值之和最大 I 解法1&#xff1a;贪心 从大到下排序矩阵所有值, 记为数组v。 转化此题&#xff1a;从r*c个数中选取3个数分别给到车1&#xff0c;车2&#xff0c;和车3&#xff0c;使得符合条件的三数之和最大。…

rancher upgrade 【rancher 升级】

文章目录 1. 背景2. 下载3. 安装4. 检查5. 测试5.1 创建项目5.2 创建应用5.3 删除集群5.4 注册集群 1. 背景 rancher v2.8.2 升级 v2.9.1 2. 下载 下载charts helm repo add rancher-latest https://releases.rancher.com/server-charts/latest helm repo update helm fetc…

NIO、Reactor模式与直接内存

1.NIO NIO有三大核心组件&#xff1a;Selector选择器、Channel管道、buffer缓冲区。、 1.1Selector Selector的英文含义是“选择器”&#xff0c;也可以称为为“轮询代理器”、“事件订阅器”、“channel容器管理机”都行。 Java NIO的选择器允许一个单独的线程来监视多个输…

鸿蒙MPChart图表自定义(四)短刻度线

对于图表中的x轴效果&#xff0c;我们有时想要实现如图所示的特定刻度线。若需绘制x轴的短刻度线&#xff0c;我们可以利用现有资源&#xff0c;将原本的网格线稍作修改&#xff0c;只需绘制一条简洁的短线即可达到目的。 具体的方法就是写一个类MyXAxisRender继承自XAxisRend…

iOS——runLoop

什么是runloop RunLoop实际上就是一个对象&#xff0c;这个对象管理了其需要处理的事件和消息&#xff0c;并提供了一个入口函数来执行相应的处理逻辑。线程执行了这个函数后&#xff0c;就会处于这个函数内部的循环中&#xff0c;直到循环结束&#xff0c;函数返回。 RunLoo…

【转载】golang内存分配

Go 的分配采用了类似 tcmalloc 的结构.特点: 使用一小块一小块的连续内存页, 进行分配某个范围大小的内存需求. 比如某个连续 8KB 专门用于分配 17-24 字节,以此减少内存碎片. 线程拥有一定的 cache, 可用于无锁分配. 同时 Go 对于 GC 后回收的内存页, 并不是马上归还给操作系…

Android13 Hotseat客制化--Hotseat修改布局、支持滑动、去掉开机弹动效果、禁止创建文件夹

需求如题&#xff0c;实现效果如下 &#xff1a; 固定Hotseat的padding位置、固定高度 step1 在FeatureFlags.java中添加flag,以兼容原生态代码 public static final boolean STATIC_HOTSEAT_PADDING true;//hotseat area fixed step2:在dimens.xml中添加padding值和高度值…

信息系统安全保障

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 0x01&#xff1a;信息系统 信息系统是具有集成性的系统&#xff0c;每一个组织中信息流动的综合构成一个信息系统。信息系统是根据一定的需要进行输入、系统控制、数据处理、数据存储与输出等活动…

职场关系课:职场上的基本原则(安全原则、进步原则、收益原则、逃生舱原则)

文章目录 引言安全原则进步原则收益原则逃生舱原则引言 职场上的王者,身体里都应该有三个灵魂: 一个文臣,谨小慎微,考虑风险; 一个武将,积极努力,谋求胜利; 一个商人,精打细算,心中有数。 安全原则 工作安全:保住自己的工作和位置信用安全:保住个人的信用,如果领…

《征服数据结构》差分数组

摘要&#xff1a; 1&#xff0c;差分数组的介绍 2&#xff0c;二维差分数组的介绍 1&#xff0c;差分数组的介绍 差分数组主要是操作区间的&#xff0c;关于区间操作的数据结构比较多&#xff0c;除了前面讲的《稀疏表》&#xff0c;还有树状数组&#xff0c;线段树&#xff0c…