硬件:
舵机(伺服电机)伺服电机就是带有反馈环节的电机,我们可以通过伺服电机进行精确的位置控制或者输出较高的扭矩。
内部结构:
-
①:信号线:接收来自微控制器的控制信号;
-
②:电位器:可以测量输出轴的位置量,属于整个伺服机构的反馈部分;
-
③:内部控制器:处理来自外部控制的信号,驱动电机以及处理反馈的位置信号,是整个伺服机构的核心;
-
④:电机:作为执行机构,输出多少转速,转矩,位置;
-
⑤:传动机构/舵机系统:该机构根据一定传动比,将电机输出的行程缩放到最终输出的角度上;
因此舵机是伺服电机的一种,整体电机就是一个闭环系统,输入相应的信号,就能控制舵机输出对应的位置量;
控制原理:
产品型号 MG995
产品重量 55g
工作扭矩 13KG/cm
反应转速 53-62R/M
使用温度 -30~+60°
死区设定 4微秒
插头类型 JR、FUTABA通用
转动角度 最大180度
舵机类型 模拟舵机
工作电流 100mA
使用电压 3-7.2V
结构材质 金属铜齿、空心杯电机、双滚珠轴承 无负载
操作速度 0.17秒/60度(4.8V);0.13秒/60度(6.0V)
接线:
使用原理:
舵机的控制一般需要一个20ms的脉冲,角度对应如下:
t = 0.5ms——————-舵机会转动 0 °
t = 1.0ms——————-舵机会转动 45°
t = 1.5ms——————-舵机会转动 90°
t = 2.0ms——————-舵机会转动 135°
t = 2.5ms——————-舵机会转动180°
所以转的角度也就取决于高电平在这段20ms周期中的时间(占空比)。
蓝牙控制双路舵机程序:
/*******************************************
* 蓝牙控制两路舵机
* 蓝牙发送 1-180 表示:舵机1-180度
*******************************************/
#include <SoftwareSerial.h>
#include <Servo.h>
#include "U8glib.h"
int pos, pos1, pos2; //舵机角度
uint8_t dataIndex = 0; //初始状态
Servo myServo1, myServo2; //创建Servo对象myServo
SoftwareSerial BTserial(10, 11); // 建立SoftwareSerial对象,RX引脚2, TX引脚3
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are SCK = 13 and MOSI = 11)
static unsigned char deng[] U8G_PROGMEM = {0x00,0x00,0x7E,0x3E,0x40,0x22,0x40,0x12,0x42,0x12,0x24,0x0A,0x28,0x12,0x10,0x12,
0x10,0x22,0x28,0x22,0x28,0x22,0x44,0x16,0x42,0x0A,0x01,0x02,0x00,0x02,0x00,0x02,/*"邓",0*/};
static unsigned char zhao[] U8G_PROGMEM = {0x00,0x00,0xBE,0x3F,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x29,0xBE,0x10,0x22,0x3F,
0x22,0x21,0x22,0x21,0x22,0x21,0x3E,0x3F,0x00,0x00,0x12,0x11,0x22,0x22,0x21,0x22,/*"照",1*/};
static unsigned char quan[] U8G_PROGMEM = {0x08,0x00,0xC8,0x3F,0x88,0x20,0x88,0x20,0xBF,0x20,0x08,0x11,0x0C,0x11,0x1C,0x11,
0x2A,0x0A,0x2A,0x0A,0x09,0x04,0x08,0x04,0x08,0x0A,0x08,0x11,0x88,0x20,0x68,0x40,/*"权",2*/};
void draw0(void) {
u8g.drawXBMP( 0, 0, 16, 16, deng);
u8g.drawXBMP( 16, 0, 16, 16, zhao);
u8g.drawXBMP( 32, 0, 16, 16, quan);
u8g.setFont(u8g_font_unifont);
u8g.drawStr( 50, 14, "190306238");
u8g.drawStr( 0, 45, "Servo2:");
u8g.drawStr( 0, 30, "Servo1:");
//舵机1
u8g.setPrintPos(60,30);
u8g.print(pos1);
//舵机2
u8g.setPrintPos(60,45);
u8g.print(pos2);
//默认
if(dataIndex == 0){
u8g.drawStr( 0, 60, "Please Open BLE!");
}
}
void LED_Show(void)
{
u8g.firstPage();
do {
draw0();
} while( u8g.nextPage() );
}
void setup() {
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
digitalWrite(8, HIGH);
digitalWrite(9, LOW);
Serial.begin(9600);
BTserial.begin(9600); // HC-06 默认波特率 9600
Serial.print("HC-05 DEMO/TEST ");
BTserial.print("AT"); //可在此处输入设置HC-06蓝牙模块的AT指令。
//此AT指令须在HC-06未连接蓝牙状态输入。
pinMode(13, OUTPUT);
myServo1.attach(3); //舵机1
myServo2.attach(5); //舵机2
LED_Show();
}
void loop(){
// 通过串口监视器显示HC-06发送的数据
if( BTserial.available()>0 ){ //如果软件串口有HC-06发来的数据
String BTserialData = BTserial.readStringUntil('-'); //将软件串口中的数据赋值给变量BTserialData
Serial.println( BTserialData ); //通过硬件串口监视器显示HC-06发来的数据
if (BTserialData == "1") { //判断HC-06发来的数据是否是字符1
pos = BTserial.parseInt(); // 解析串口数据中的整数信息并赋值给变量pos
pos1 = pos;
Serial.println(pos); // 通过串口监视器显示变量pos数值
myServo1.write(pos);
dataIndex = 1;
LED_Show();
}
else if (BTserialData == "2") { //第二个舵机
int pos = BTserial.parseInt(); // 解析串口数据中的整数信息并赋值给变量pos
Serial.println(pos); // 通过串口监视器显示变量pos数值
pos2 = pos;
myServo2.write(pos);
dataIndex = 2;
LED_Show(); //LED显示
}
}
// 将用户通过串口监视器输入的数据发送给HC-06
if (Serial.available()>0) { //如果硬件串口缓存中有等待传输的数据
char serialData = Serial.read(); //将硬件串口中的数据赋值给变量serialData
BTserial.print( serialData ); //将硬件串口中的数据发送给HC-06
}
}
多路程序驱动:
#include <Servo.h>
Servo base, fArm, rArm, claw; //建立4个电机对象
int dataIndex = 0;
void setup() {
base.attach(11); // base 伺服电机连接引脚11 电机代号'b'
rArm.attach(10); // rArm 伺服电机连接引脚10 电机代号'r'
fArm.attach(9); // fArm 伺服电机连接引脚9 电机代号'f'
claw.attach(6); // claw 伺服电机连接引脚6 电机代号'c'
Serial.begin(9600);
Serial.println("Please input serial data.");
}
void loop() {
if (Serial.available()) { // 检查串口缓存是否有数据等待传输
char servoName = Serial.read(); //获取电机指令中电机编号信息
Serial.print("servoName = ");
Serial.print(servoName);
Serial.print(" , ");
int data = Serial.parseInt(); //获取电机指令中电机角度信息
switch(servoName){ //根据电机指令中电机信息决定对哪一个电机进行角度设置
case 'b': // 电机指令b,设置base电机角度
base.write(data);
Serial.print("Set base servo value: ");
Serial.println(data);
break;
case 'r': // 电机指令r,设置rArm电机角度
rArm.write(data);
Serial.print("Set rArm servo value: ");
Serial.println(data);
break;
case 'f': // 电机指令f,设置fArm电机角度
fArm.write(data);
Serial.print("Set fArm servo value: ");
Serial.println(data);
break;
case 'c': // 电机指令c,设置claw电机角度
claw.write(data);
Serial.print("Set claw servo value: ");
Serial.println(data);
break;
}
}
}
单路程序驱动:
Servo myservo; // 创建Servo对象用以控制伺服电机
// 很多开发板允许同时创建12个Servo对象
int pos = 0; // 存储伺服电机角度信息的变量
void setup() {
myservo.attach(9); // Servo对象连接在9号引脚
Serial.begin(9600);
}
void loop() {
for (pos = 0; pos <= 180; pos += 45) { // 0度转到180度
// 每一步增加1度
myservo.write(pos); // 告诉伺服电机达到'pos'变量的角度
Serial.println(pos);
delay(1000); // 等待15毫秒以确保伺服电机可以达到目标角度
}
for (pos = 180; pos >= 0; pos -= 45) { // 180度转到0度
myservo.write(pos); // 告诉伺服电机达到'pos'变量的角度
Serial.println(pos);
delay(1000); // 等待15毫秒以确保伺服电机可以达到目标角度
}
}