当前位置: 首页 > news >正文

ESP32项目(三、控制继电器,伺服电机,舵机)

目录

一、控制继电器从而控制电机

1.接线

2.代码

二、ESP32控制伺服电机

1.硬件型号

2.ESP32的CAN通讯介绍

3.接线

4.代码

三、ESP32控制舵机

1.型号

(1)180°

(2)360°

2.舵机电源板

3.接线

4.代码


一、控制继电器从而控制电机

1.接线

我的继电器上面写了5V,我是用ESP32的3V3接上没有问题。

2.代码

#define RELAY_PIN 25void setup() {pinMode(RELAY_PIN, OUTPUT);digitalWrite(RELAY_PIN, LOW); // 初始关闭
}void loop() {digitalWrite(RELAY_PIN, HIGH); // 吸合,负载开启delay(2000);// digitalWrite(RELAY_PIN, LOW);  // 释放,负载关闭// delay(2000);
}

注意:

1.继电器闭合和开启会有声音。

2.继电器闭合时候绿灯会亮,接上芯片之后红灯会亮

二、ESP32控制伺服电机

1.硬件型号

基本参数

2.ESP32的CAN通讯介绍

ESP32自带twai,支持can通讯,所以只需要买一个can转换器就好了。

3.接线

4.代码

#include <Arduino.h>
#include "driver/twai.h"// === CAN 引脚 ===
#define CAN_TX 5
#define CAN_RX 4// Node ID
#define NODE_X 1
#define NODE_Y 2
#define NODE_Z 3// 状态/位置
volatile bool xReached = false, yReached = false, zReachedFlag = false;
volatile int32_t posX_actual = 0, posY_actual = 0, posZ_actual = 0;// “软件原点”偏移(上电或手动置零时记录)
int32_t originX = 0, originY = 0, originZ = 0;
bool haveX0=false, haveY0=false, haveZ0=false;// 机械参数(按你实际修改:丝杆螺距、编码器计数/圈、减速比等)
const float pitch_mm_per_rev_X = 5.0f;
const float pitch_mm_per_rev_Y = 5.0f;
const float pitch_mm_per_rev_Z = 5.0f;
const int   counts_per_rev     = 32768; // 若你的电机不同,请改这里
const float gear_ratio         = 1.0f;  // 有减速箱就填减速比,否则1.0// === 修改电机 Node-ID ===
// oldId: 当前电机的地址(比如现在是1)
// newId: 想改成的新地址(比如改成3)
void changeNodeID(uint8_t oldId, uint8_t newId) {// Step 1. 写入新地址uint8_t cmd_setAddr[8] = {0x2B, 0x15, 0x26, 0x00, newId, 0x00, 0x00, 0x00};sendCAN(0x600 + oldId, cmd_setAddr, 8);delay(10);// Step 2. 参数保存uint8_t cmd_save[8] = {0x2B, 0x14, 0x26, 0x00, 0x01, 0x00, 0x00, 0x00};sendCAN(0x600 + oldId, cmd_save, 8);delay(10);Serial.printf("已发送修改地址命令:Node %d → %d,请断电重启。\n", oldId, newId);
}// === 发送 CAN 帧 ===
void sendCAN(uint32_t can_id, const uint8_t *data, uint8_t len) {twai_message_t m{};m.identifier = can_id;m.data_length_code = len;m.rtr = 0; m.extd = 0;for (int i=0;i<len;i++) m.data[i]=data[i];twai_transmit(&m, pdMS_TO_TICKS(100));
}// NMT start
void nmtStart(uint8_t nodeId) {uint8_t d[2] = {0x01, nodeId};sendCAN(0x000, d, 2);
}// 设置绝对目标位置(RPDO4,缓存,等 SYNC 执行)
void setTargetPosition(uint8_t nodeId, int32_t pos) {uint8_t d[4] = {(uint8_t)(pos & 0xFF),(uint8_t)((pos>>8) & 0xFF),(uint8_t)((pos>>16)& 0xFF),(uint8_t)((pos>>24)& 0xFF)};sendCAN(0x500 + nodeId, d, 4);
}// 发送 SYNC(触发 RPDO4 同步执行)
void sendSync() { sendCAN(0x080, nullptr, 0); }// Z 轴单独移动(不走 SYNC;你的电机若支持 RPDO2 目标位置+速度也可用)
void moveZ_abs(int32_t pos) {uint8_t d[7];d[0]=0x2F; d[1]=0x00; d[2]=0x01; // 控制字/模式示例;按你的电机映射如需调整d[3]=(uint8_t)(pos & 0xFF);d[4]=(uint8_t)((pos>>8) & 0xFF);d[5]=(uint8_t)((pos>>16)& 0xFF);d[6]=(uint8_t)((pos>>24)& 0xFF);sendCAN(0x200 + NODE_Z, d, 7);
}// 处理 TPDO1:实际位置(4B) + 状态字(2B)
void handleTPDO(const twai_message_t &msg) {if (msg.identifier < 0x180 || msg.identifier > 0x1FF || msg.data_length_code < 6) return;uint8_t nodeId = msg.identifier - 0x180;int32_t actual = (int32_t)((uint32_t)msg.data[0] |((uint32_t)msg.data[1]<<8) |((uint32_t)msg.data[2]<<16)|((uint32_t)msg.data[3]<<24));uint16_t sw = (uint16_t)(msg.data[4] | (msg.data[5]<<8));bool reached = sw & (1<<10);if (nodeId==NODE_X) { posX_actual=actual; xReached=reached; if(!haveX0){haveX0=true;} }if (nodeId==NODE_Y) { posY_actual=actual; yReached=reached; if(!haveY0){haveY0=true;} }if (nodeId==NODE_Z) { posZ_actual=actual; zReachedFlag=reached; if(!haveZ0){haveZ0=true;} }
}// cm(绝对) -> 绝对脉冲(以“软件原点”为 0)
int32_t cmAbsToPulseX(float x_cm_abs){float mm = x_cm_abs*10.0f;float counts_per_mm = (counts_per_rev*gear_ratio)/pitch_mm_per_rev_X;return (int32_t)llround(mm*counts_per_mm) - originX;
}
int32_t cmAbsToPulseY(float y_cm_abs){float mm = y_cm_abs*10.0f;float counts_per_mm = (counts_per_rev*gear_ratio)/pitch_mm_per_rev_Y;return  (int32_t)llround(mm*counts_per_mm) - originY;
}
int32_t cmAbsToPulseZ(float z_cm_abs){float mm = z_cm_abs*10.0f;float counts_per_mm = (counts_per_rev*gear_ratio)/pitch_mm_per_rev_Z;return (int32_t)llround(mm*counts_per_mm) - originZ;
}// 等待首次位置上报并把“当前位置”记为软件原点
void captureSoftwareZero() {uint32_t t0 = millis();while (!(haveX0 && haveY0 && haveZ0) && (millis()-t0)<3000) {twai_message_t rx;if (twai_receive(&rx, pdMS_TO_TICKS(50)) == ESP_OK) handleTPDO(rx);}originX = posX_actual; originY = posY_actual; originZ = posZ_actual;Serial.printf("Software zero set. originX=%ld originY=%ld originZ=%ld\n",(long)originX,(long)originY,(long)originZ);
}void setup(){Serial.begin(115200);twai_general_config_t g = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)CAN_TX,(gpio_num_t)CAN_RX,TWAI_MODE_NORMAL);// twai_timing_config_t  t = {.brp=4,.tseg_1=15,.tseg_2=4,.sjw=3,.triple_sampling=false}; // 500kbpstwai_timing_config_t t = {.brp = 4,           // 分频.tseg_1 = 15,       // 时间段1.tseg_2 = 4,        // 时间段2.sjw = 3,           // 重同步跳宽.triple_sampling = false
}; // 1 Mbpstwai_filter_config_t  f = TWAI_FILTER_CONFIG_ACCEPT_ALL();if (twai_driver_install(&g,&t,&f)==ESP_OK) Serial.println("CAN Driver installed");if (twai_start()==ESP_OK)                    Serial.println("CAN Driver started");nmtStart(NODE_X); nmtStart(NODE_Y); nmtStart(NODE_Z);delay(200);// 读取一次 TPDO,把“当前绝对脉冲”作为软件原点captureSoftwareZero();//  改Node id// changeNodeID(1, 2);}void loop(){// 这里输入“绝对坐标(以原点为0)”,单位 cmfloat x_cm_abs = 10.0f;float y_cm_abs = 20.0f;float z_cm_abs = 40.0f;// 目标绝对脉冲(基于统一原点)int32_t x_target = cmAbsToPulseX(x_cm_abs);int32_t y_target = cmAbsToPulseY(y_cm_abs);int32_t z_target = cmAbsToPulseZ(z_cm_abs);z_target = 3276700;// Serial.println(z_target);// // // 1) XY 同步到绝对目标// xReached=false; yReached=false;// setTargetPosition(NODE_X, x_target);// setTargetPosition(NODE_Y, y_target);// delay(5);// sendSync();// Serial.println("XY start move");// while (!(xReached && yReached)) {//   twai_message_t rx;//   if (twai_receive(&rx, pdMS_TO_TICKS(10)) == ESP_OK) handleTPDO(rx);// }// Serial.println("XY reached (absolute).");// delay(3000);// 2) Z 单独到绝对目标zReachedFlag=false;moveZ_abs(z_target);while (!zReachedFlag) {twai_message_t rx;if (twai_receive(&rx, pdMS_TO_TICKS(10)) == ESP_OK) handleTPDO(rx);}// Serial.println("Z reached (absolute).");delay(3000);
}

三、ESP32控制舵机

这里舵机有180°和360°两种

1.型号

(1)180°

(2)360°

2.舵机电源板

3.接线

4.代码

#include <Arduino.h>// 舵机引脚
#define SERVO_180_PIN 18   // 180°舵机
#define SERVO_360_PIN 19   // 360°舵机// LEDC 通道定义
#define SERVO_180_CH 0
#define SERVO_360_CH 1// PWM 配置
#define SERVO_FREQ 50           // 50Hz
#define SERVO_RESOLUTION 16     // 分辨率 16位 (0-65535)// 当前角度记录
int currentAngle_180 = 0;
int currentAngle_360 = 0;void setup() {Serial.begin(115200);delay(500);// 配置 PWM 通道ledcSetup(SERVO_180_CH, SERVO_FREQ, SERVO_RESOLUTION);ledcSetup(SERVO_360_CH, SERVO_FREQ, SERVO_RESOLUTION);// 将通道绑定到 GPIOledcAttachPin(SERVO_180_PIN, SERVO_180_CH);ledcAttachPin(SERVO_360_PIN, SERVO_360_CH);// 初始位置setServoAngle(SERVO_180_CH, 0, 180);setServoAngle(SERVO_360_CH, 0, 360);
}void loop() {// ===== 180°舵机平滑转动 =====// smoothServoMove(SERVO_180_CH, currentAngle_180, 0, 180, 10);// smoothServoMove(SERVO_180_CH, currentAngle_180, 90, 180, 10);// smoothServoMove(SERVO_180_CH, currentAngle_180, 180, 180, 10);// ===== 360°舵机平滑转动 =====// smoothServoMove(SERVO_360_CH, currentAngle_360, 0, 360, 5);// smoothServoMove(SERVO_360_CH, currentAngle_360, 180, 360, 5);// smoothServoMove(SERVO_360_CH, currentAngle_360, 360, 360, 5);setServoAngle(SERVO_360_CH, 0, 360);delay(5000);setServoAngle(SERVO_360_CH, 90, 360);delay(5000);setServoAngle(SERVO_360_CH, 180, 360);delay(5000);setServoAngle(SERVO_360_CH, 270, 360);delay(5000);setServoAngle(SERVO_360_CH, 350, 360);}// ========== 单步设置舵机角度 ==========
void setServoAngle(int channel, int angle, int maxAngle) {angle = constrain(angle, 0, maxAngle);int us = map(angle, 0, maxAngle, 500, 2500);uint32_t duty = (uint32_t)((float)us / 20000.0 * 65535);  // 20ms 周期ledcWrite(channel, duty);// 保存当前角度if (channel == SERVO_180_CH) currentAngle_180 = angle;if (channel == SERVO_360_CH) currentAngle_360 = angle;
}// ========== 平滑转动函数 ==========
// channel: 通道
// fromAngle: 当前角度
// toAngle:   目标角度
// maxAngle:  舵机最大角度(180 或 360)
// stepDelay: 每步延时(ms),越大越慢
void smoothServoMove(int channel, int fromAngle, int toAngle, int maxAngle, int stepDelay) {if (fromAngle == toAngle) return;int step = (fromAngle < toAngle) ? 1 : -1;  // 方向判断for (int angle = fromAngle; angle != toAngle; angle += step) {setServoAngle(channel, angle, maxAngle);delay(stepDelay);}// 最后确保精确停在目标角度setServoAngle(channel, toAngle, maxAngle);// 打印当前状态Serial.print("[SERVO] 通道 ");Serial.print(channel);Serial.print(" 平滑转到 ");Serial.print(toAngle);Serial.println("°");
}

http://www.dtcms.com/a/453633.html

相关文章:

  • Python 3 内置函数详解
  • Spring AI快速入门以及项目的创建
  • 微网站制作工具有哪些霞浦建设局总规网站
  • 免费微商城网站建设网站开发团队人员构成
  • 个人网页简单模板下载seo是怎么优化的
  • 杭州有实力的网站开发直接通过域名访问wordpress
  • 多目标识别YOLO :YOLOV3 原理
  • 【Qt】QSS
  • 反射还是代码生成?Go反射使用的边界与取舍|Go语言进阶(11)
  • 国际外贸网站建设前端自适应模板
  • 网站建设代码流程花店网站建设个人小结
  • 德阳建设公司网站网站制作里的更多怎么做
  • HandBrake:视频压缩工具
  • 建设部门的网站wordpress图片批量上传插件下载
  • 致远OA配置HTTPS访问避坑帖
  • 快速搭建网站视频wordpress托管在哪里
  • AssemblyScript 入门教程(5):深入理解 TypedArray
  • 【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
  • STM32G474单片机开发入门(六)定时器TIMER详解及实战含源码
  • C++进阶(9)——智能指针的使用及其原理
  • 个人写HTOS移植shell
  • 【开发工具】Windows1011远程Ubuntu18及以上桌面
  • 输入法网站设计怎么自己制作图片
  • STM32 Flash 访问加速器详解(ART Accelerator)
  • stm32 freertos下基于hal库的模拟I2C驱动实现
  • 成都微网站访问wordpress速度慢
  • 意识形态网站建设怎么做网络平台
  • LangChain部署RAG part1(背景概念)(赋范大模型社区公开课听课笔记)
  • 模块化html5网站开发本地网站后台管理建设
  • 在源码之家下载的网站模板可以作为自己的网站吗资讯网站的好处