arduino uno R3驱动直流减速电机(蓝牙控制)
此篇博客用于记录使用arduino驱动直流减速电机的过程,仅实现简单的功能:PID调速、蓝牙控制
- 1、直流减速电机简介
- 2、DRV8833电机驱动模块简介
- 3、HC-05蓝牙模块简介
- 电机转动测试
- 4、PID控制
- 5、蓝牙控制电机
1、直流减速电机简介
我在淘宝购买的电机,减速比是21.3,旋转一圈产生的脉冲数是11,这样实际通过编码区采集到的一圈脉冲数(使用一倍频计数)是11×21.3,如果采用N倍频的话就是:11×21.3×N。这里关于编码器的相关知识直接看此文档有详细介绍:http://www.autolabor.com.cn/book/ROSTutorials/di-8-zhang-gou-jian-lun-shi-cha-fen-ji-qi-ren/83-di-pan-kong-zhi-ji-chu-arduino-yu-dian-ji-qu-dong/833-dian-ji-ce-su.html

上面给出了接线方式,要注意的是直接使用arduino的io口是无法驱动电机的,所以还需要一块电机驱动板或者驱动芯片,这里使用的是DRV8833电机驱动模块,红色接DRV8833的AO1、白色接DRV8833的AO2、黑色接arduino的GND、蓝色接3V3、因为使用一倍频,只需要一个中断口就可以,这里换黄色接引脚2(外部中断),绿色接引脚9(可以使用其他的io口)。
2、DRV8833电机驱动模块简介
下面是芯片引脚图


由于这里VM需要较高的电压才能驱动电机转起来,所以还单独购买了一个电池,用于VM引脚供电,电池名称:18650锂电池,最好选可以充电的那种。
AIN1接arduino的引脚10(需要可以输出pwm波的引脚),AIN2接引脚11(可以任意指定引脚,这只是用于控制方向),STBY引脚直接接5V。


3、HC-05蓝牙模块简介

一共六个引脚,EN和STATE一般用不到,其余的有两个电源引脚、两个串口引脚。建议在使用单片机调试之前先用usb转ttl模块连接电脑进行测试:①将RX连接至usb转ttl模块的TX,TX连接RX,电源线对着连。②插进电脑之前先按住HC-05上的按键,然后将usb转ttl模块插入电脑,此时HC-05就会进入AT指令状态下,可以使用电脑的串口助手进行测试,蓝牙模块的波特率默认是38400,0个停止位,0个校验位。③进行测试,发送指令的顺序可以参考这个:1、AT,返回OK;2、AT+ROLE=0,默认就是零,保险起见再设置一下,设置完这个之后,下一次上电周围的设备就可以搜索到此蓝牙;3、AT+NAME=xxx,这里按自己喜好设置名字;4、AT+PSWD=“xxx”,设定密码;5、AT+UART=38400,0,0。设置波特率和停止位、校验位。
这样就设置完成了,下一次可以直接上电,然后手机搜索蓝牙使用密码连接。如果不想用串口助手测试,也可以再arduino中用以下代码测试(蓝牙模块的RX连接arduino引脚9,TX连引脚8):
#include <SoftwareSerial.h> //库文件SoftwareSerial BT(8, 9); //设置蓝牙与板子的连接端口。 pin 8 接蓝牙的 TXD pin 9 接蓝牙的 RXD
char X; //定义一个变量存数据。void setup()
{Serial.begin(38400); //串口监视器通信速率,38400Serial.println("蓝牙连接正常"); //串口监视器显示蓝牙正常状态BT.begin(38400); //蓝牙通信速率,默认一般为 38400
}void loop() //大循环,执行。
{if (Serial.available()) {X = Serial.read(); //把写入的数据给到自定义变量 XBT.print(X); //由arduino向手机发数据}if (BT.available()) {X = BT.read(); //把检测到的数据给到自定义变量 XSerial.print(X); //由手机向arduino发数据}
}
编译运行之后打开自带的串口监视器,设置模式BOTH NL &CR,波特率选择38400,就可以输入前面的指令进行设置了,后面与手机进行通信的时候发现数据都是乱码,将 BT.begin(38400); 改为 BT.begin(9600);即可。
电机转动测试
按照上面的方式连接好线路之后可以先测试看是否能正常驱动电机转起来:
/** 电机转动控制* 1.定义接线中电机对应的引脚* 2.setup 中设置引脚为输出模式* 3.loop中控制电机转动* */int DIRA = 11;
int PWMA = 10;void setup() {//两个引脚都设置为 OUTPUTpinMode(DIRA,OUTPUT);pinMode(PWMA,OUTPUT);
}void loop() {//先正向转动3秒digitalWrite(DIRA,LOW);analogWrite(PWMA,100);delay(3000);//停止3秒digitalWrite(DIRA,LOW);analogWrite(PWMA,0);delay(3000);//再反向转动3秒digitalWrite(DIRA,HIGH);analogWrite(PWMA,100);delay(3000);//停止3秒digitalWrite(DIRA,LOW);analogWrite(PWMA,0);delay(3000);/** 注意: * 1.可以通过将DIRA设置为HIGH或LOW来控制电机转向,但是哪个标志位正转或反转需要根据需求判断,转向是相对的。* 2.PWM的取值为 [0,255],该值可自己设置。* */
}
如果电机转动起来说明前面的步骤就没问题。
转速测试也直接参考前面的那个链接里做就行。
4、PID控制
理论部分参考链接文档,下面给出具体实现流程:
也就是直接调用PID库里的函数就可以实现,具体代码如下:
#include <PID_v1.h> int motor_A = 2;//中端口是2
int motor_B = 9;//中断口是3
int DIRA = 11;
int PWMA = 10;
volatile int count = 0;//如果是正转,那么每计数一次自增1,如果是反转,那么每计数一次自减1 float reducation = 21;//减速比,根据电机参数设置,比如 15 | 30 | 60
int pulse = 11; //编码器旋转一圈产生的脉冲数该值需要参考商家电机参数
int per_round = pulse * reducation;//车轮旋转一圈产生的脉冲数
long start_time = millis();//一个计算周期的开始时刻,初始值为 millis();
long interval_time = 50;//一个计算周期 50ms
double current_vel;void count_A(){//单频计数实现//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比if(digitalRead(motor_A) == HIGH){if(digitalRead(motor_B) == HIGH){//A 高 B 高count++; } else {//A 高 B 低count--; }}
}//获取当前转速的函数
void get_current_vel(){long right_now = millis(); long past_time = right_now - start_time;//计算逝去的时间if(past_time >= interval_time){//如果逝去时间大于等于一个计算周期//1.禁止中断noInterrupts();//2.计算转速 转速单位可以是秒,也可以是分钟... 自定义即可current_vel = (double)(count) / per_round / past_time * 1000 * 60;//3.重置计数器count = 0;//4.重置开始时间start_time = right_now;//5.重启中断interrupts();Serial.println(current_vel);}
}//-------------------------------------PID-------------------------------------------
//创建 PID 对象
//1.当前转速 2.计算输出的pwm 3.目标转速 4.kp 5.ki 6.kd 7.当输入与目标值出现偏差时,向哪个方向控制
double pwm;//电机驱动的PWM值
double target = 20;
double kp=1.5, ki=3.0, kd=0.1;
PID pid(¤t_vel,&pwm,&target,kp,ki,kd,DIRECT);//速度更新函数
void update_vel(){//获取当前速度get_current_vel();pid.Compute();//计算需要输出的PWMdigitalWrite(DIRA,HIGH);analogWrite(PWMA,pwm);}void setup() {Serial.begin(57600);//设置波特率 pinMode(9,INPUT);pinMode(2,INPUT);pinMode(10,OUTPUT);pinMode(11,OUTPUT);attachInterrupt(0,count_A,CHANGE);//当电平发生改变时触发中断函数pid.SetMode(AUTOMATIC);
}void loop() {delay(10);update_vel();
}
PID控制的最终预期结果,是要快速、精准、稳定的达成预期结果,P主要用于控制响应速度,I主要用于控制精度,D主要用于减小震荡增强系统稳定性,三者的取值是需要反复调试的,调试过程中需要查看系统的响应曲线,根据响应曲线以确定合适的PID值。
在 Arduino 中响应曲线的查看可以借助于 Serial.println() 将结果输出,然后再选择菜单栏的工具下串口绘图器以图形化的方式显示响应结果
5、蓝牙控制电机
这里只提供简单实现,可以用安卓手机市场里的蓝牙调试器进行调试,如果找不到也可以私信我。实现控制电机正反转。
#include <SoftwareSerial.h>
#include <PID_v1.h> SoftwareSerial BT(8, 9); //设置蓝牙与板子的连接端口。 pin 8 接蓝牙的 TXD pin 9 接蓝牙的 RXD
char X; //定义一个变量存数据。
String temp = "";int motor_A = 2;//中端口是2
int motor_B = 9;//中断口是3
int DIRA = 11;
int PWMA = 10;
volatile int count = 0;//如果是正转,那么每计数一次自增1,如果是反转,那么每计数一次自减1 float reducation = 21.3;//减速比,根据电机参数设置,比如 15 | 30 | 60
int pulse = 11; //编码器旋转一圈产生的脉冲数该值需要参考商家电机参数
int per_round = pulse * reducation;//车轮旋转一圈产生的脉冲数
long start_time = millis();//一个计算周期的开始时刻,初始值为 millis();
long interval_time = 50;//一个计算周期 50ms
double current_vel;void count_A(){//单频计数实现//手动旋转电机一圈,输出结果为 一圈脉冲数 * 减速比if(digitalRead(motor_A) == HIGH){if(digitalRead(motor_B) == HIGH){//A 高 B 高count++; } else {//A 高 B 低count--; }}
}//获取当前转速的函数
void get_current_vel(){long right_now = millis(); long past_time = right_now - start_time;//计算逝去的时间if(past_time >= interval_time){//如果逝去时间大于等于一个计算周期//1.禁止中断noInterrupts();//2.计算转速 转速单位可以是秒,也可以是分钟... 自定义即可current_vel = (double)(count) / per_round / past_time * 1000 * 60;//3.重置计数器count = 0;//4.重置开始时间start_time = right_now;//5.重启中断interrupts();Serial.println(current_vel);}
}//-------------------------------------PID-------------------------------------------
//创建 PID 对象
//1.当前转速 2.计算输出的pwm 3.目标转速 4.kp 5.ki 6.kd 7.当输入与目标值出现偏差时,向哪个方向控制
double pwm;//电机驱动的PWM值
double target = 0;
double kp=1.5, ki=3.0, kd=0.1;
PID pid(¤t_vel,&pwm,&target,kp,ki,kd,DIRECT);//速度更新函数
void update_vel(){//获取当前速度get_current_vel();pid.Compute();//计算需要输出的PWMif(target > 0){digitalWrite(DIRA,LOW); //正转}else if(target < 0){digitalWrite(DIRA,HIGH);//反转}else{}analogWrite(PWMA,pwm);}void setup() {Serial.begin(38400);//设置波特率 pinMode(9,INPUT);pinMode(2,INPUT);pinMode(10,OUTPUT);pinMode(11,OUTPUT);attachInterrupt(0,count_A,CHANGE);//当电平发生改变时触发中断函数pid.SetMode(AUTOMATIC);BT.begin(9600);
}void loop() {if (BT.available()) //检测:【蓝牙】如果数据写入,则执行。{X = BT.read(); //把检测到的数据给到自定义变量 XSerial.println(X); //把从蓝牙得到的数据显示到串口监视器temp = X;}if(temp == "2"){target = 80;Serial.println(temp);}else if(temp == "3"){target = -80;Serial.println(temp);}else if(temp == "0"){target = 0;Serial.println(temp);}delay(10);update_vel();
}
蓝牙调试器发送2控制电机正转,发送3反转,发送0停止。
相关文章:
arduino uno R3驱动直流减速电机(蓝牙控制)
此篇博客用于记录使用arduino驱动直流减速电机的过程,仅实现简单的功能:PID调速、蓝牙控制 1、直流减速电机简介2、DRV8833电机驱动模块简介3、HC-05蓝牙模块简介电机转动测试4、PID控制5、蓝牙控制电机 1、直流减速电机简介 我在淘宝购买的电机&#x…...
智能家居控制系统(51单片机)
smart_home_control_system 51单片机课设,智能家居控制系统 使用及转载请标明出处(最好点个赞及star哈哈) Github地址,带有PPT及流程图 Gitee码云地址,带有PPT及流程图 以STC89C52为主控芯片,以矩阵键…...
软考高级系统分析师之 URL 知识点和例题
一、AI 解读 URL(统一资源定位器)的结构是网络上定位资源的一种方式。一个典型的URL由几个部分组成: 协议(Scheme): 定义了用于访问资源的协议类型,如http、https、ftp等。例如,在 http://www.…...
vmware虚拟机centos中/dev/cl_server8/root 空间不够
在使用vmware时发现自己的虚拟机的/dev/cl_server8/root空间不够了,没办法安装新的服务。所以查了一下改空间的办法。 1.在虚拟机关闭的状态下,选中需要扩容的虚拟机->设置->硬件-> 硬盘->扩展->填写扩大到的值。 2.打开虚拟机ÿ…...
C++/数据结构:AVL树
目录 一、AVL树的概念 二、AVL树的实现 2.1节点定义 2.2节点插入 三、AVL树的旋转 3.1新节点插入较高左子树的左侧:右单旋 3.2新节点插入较高右子树的右侧:左单旋 3.3新节点插入较高左子树的右侧---左右:先左单旋再右单旋 3.4新节点插…...
Mysql数据库_max_allowed_packet参数详解
本文目录 参数含义查看max_allowed_packet参数值修改max_allowed_packet参数值修改配置文件方式(需要重启)直接修改配置方式(不需要重启)注意事项 出现场景 参数含义 max_allowed_packet参数指的是MySQL服务端或者客户端接收一次…...
【数仓】Hadoop集群配置常用参数说明
Hadoop集群中,需要配置的文件主要包括四个 配置核心Hadoop参数: 编辑core-site.xml文件,设置Hadoop集群的基本参数,如文件系统、Hadoop临时目录等。 配置HDFS参数: 编辑hdfs-site.xml文件,设置HDFS的相关参…...
【go从入门到精通】什么是go?为什么要选择go?
go的出生: go语言(或Golang)是Google开发的开源编程语言,诞生于2006年1月2日下午15点4分5秒,于2009年11月开源,2012年发布go稳定版。Go语言在多核并发上拥有原生的设计优势,Go语言从底层原生支持…...
MySQL篇—执行计划介绍(第二篇,总共三篇)
☘️博主介绍☘️: ✨又是一天没白过,我是奈斯,DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux,也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章,并且也会默默的点赞收藏加关注❣…...
nest.js使用nest-winston日志一
nest-winston文档 nest-winston - npm 参考:nestjs中winston日志模块使用 - 浮的blog - SegmentFault 思否 安装 cnpm install --save nest-winston winstoncnpm install winston-daily-rotate-file 在main.ts中 import { NestFactory } from nestjs/core; im…...
LeetCode刷题笔记之二叉树(四)
一、二叉搜索树的应用 1. 700【二叉搜索树中的搜索】 题目: 给定二叉搜索树(BST)的根节点 root 和一个整数值 val。你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。代码&a…...
【MATLAB源码-第150期】基于matlab的开普勒优化算法(KOA)机器人栅格路径规划,输出做短路径图和适应度曲线。
操作环境: MATLAB 2022a 1、算法描述 开普勒优化算法(Kepler Optimization Algorithm, KOA)是一个虚构的、灵感来自天文学的优化算法,它借鉴了开普勒行星运动定律的概念来设计。在这个构想中,算法模仿行星围绕太阳的…...
最佳实践:Websocket 长连接状态如何保持
WebSocket 是一种支持通过单个 TCP 连接进行全双工通信的协议,相较于传统的 HTTP 协议,它更适合需要实时交互的应用场景。此协议在现代 Web 应用中扮演着至关重要的角色,尤其是在需要实时更新和通信的场合下维持持久连接。本文将探讨 WebSock…...
Unity AStar寻路算法与导航
在游戏开发中,寻路算法是一个非常重要的部分,它决定了游戏中角色的移动路径。Unity作为一款流行的游戏开发引擎,提供了许多内置的寻路算法,其中最常用的就是AStar算法。AStar算法是一种基于图的搜索算法,通过启发式搜索…...
JavaScript最新实现城市级联操作,json格式的数据
前置知识: <button onclick"doSelect()">操作下拉列表</button><hr>学历:<select id"degree"><option value"0">--请选择学历--</option><option value"1">专科<…...
SD NAND:为车载显示器注入智能与安全的心脏
SD NAND 在车载显示器的应用 在车载显示器上,SD NAND(Secure Digital NAND)可以有多种应用,其中一些可能包括: 导航数据存储: SD NAND 可以用于存储地图数据、导航软件以及车载系统的相关信息。这有助于提…...
矩阵的对角化
概述 对角化矩阵是线性代数中的一个重要概念,它涉及将一个方阵转换成一个对角阵,这个对角阵与原矩阵相似,其主要对角线上的元素为原矩阵的特征值。这样的转换简化了很多数学问题,特别是线性动力系统的求解和矩阵的幂运算。下面是…...
React编写组件时,如何省略.tsx后缀
省略.tsx后缀 当tsconfig.json配置了,需要重启后才会生效 {"compilerOptions": {"allowJs": true,"jsx": "react-jsx",} }当进行以上配置后,导入组件时添加后缀,Eslint报错如下: An im…...
移动端的React项目中如何配置自适应和px转rem
创建项目 create-react-app project-name 启动项目 npm start 下载自适应和px转rem的插件 自适应的: npm install lib-flexible --save px转rem的:npm install postcss-pxtorem5.1.1 --save-dev 创建craco.config.js配置文件 在package.json中…...
TypeScript 结合 React 开发时候 , React.FunctionComponent 解释
在 TypeScript 结合 React 开发时,React.FC(或 React.FunctionComponent)是一个泛型类型,它用于定义函数组件的类型。这个类型定义了函数组件的结构和预期行为,并且提供了泛型支持,以便你可以指定组件 prop…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...
