1. 对比360度舵机和180度舵机控制方法小结

 

servo.write(x);  //x->[0,180];
  • 1

360度舵机:

通过x设定舵机的速度(0代表一个方向的全速运行,180代表另一个方向的全速运行,90则不动)。

#include <Servo.h> 

Servo myservo;

void setup() 
{ 
  myservo.attach(9);
  myservo.write(90);  // 舵机不动
} 

void loop() {} 

180度舵机:

通过x设定舵机舵盘的角度。

#include <Servo.h> 

Servo myservo;

void setup() 
{ 
  myservo.attach(9);
  myservo.write(90);  // 在中间位置
} 

void loop() {} 

值得注意的是如果x不等于90,360度舵机会一直不停的转。而180度舵机在到达设定角度后会停下。


writeMicroseconds()

servo.writeMicroseconds(x) //x->[1000,2000]
  • 1

360度舵机:

这个函数对于360度舵机的作用就是write()函数的模拟版,[1000,2000]对应[0,180]。比如writeMicroseconds(1500)相当于write(90),舵机不动。

180度舵机 :

通过x设定角度,一般来说1000是完全逆时针旋转后的位置,2000是完全顺时针旋转的位置,1500在中间。

注意有些制造商并不完全遵守这个标准,所以舵机经常会对700到2300之间的数值产生反应。实际数值可以自己试试。

#include <Servo.h> 

Servo myservo;

void setup() 
{ 
  myservo.attach(9);
  myservo.writeMicroseconds(1500);  // 舵机设定为中间位置。
} 

void loop() {} 

2. Arduino控制伺服电机电路连接说明

 Arduino引脚

伺服电机(舵机)

+5V

红色线-VCC

GND(接地)

棕色线-GND

9(PWM)

橙色线-PWM控制信号

2.1单个电机

/* Sweep
 by BARRAGAN <http://barraganstudio.com>
 This example code is in the public domain.

 modified 8 Nov 2013
 by Scott Fitzgerald
 http://www.arduino.cc/en/Tutorial/Sweep
*/

#include <Servo.h>

Servo myservo;  // 创建一个servo对象控制伺服电机
// 很多开发板允许同时创建12个servo对象

int pos = 0;    // 存servo电机角度的信息变量

void setup() {
  myservo.attach(9);  // servo 对象连接9号引脚上
  Serial.begin(9600);
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    Serial.println(pos);
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    Serial.println(pos);
    delay(15);                       // waits 15ms for the servo to reach the position
  }
}

 

控制伺服电机,另外接一根地线,共地

/*
本示例程序旨在演示如何通过串口监视器控制1个伺服电机(舵机)。
This example code is in the public domain.
*/
#include <Servo.h>
 
Servo myServo;         //创建Servo对象myServo
 
int dataIndex = 0;     //创建整数型变量,存储输入数据序列号
void setup() {
  myServo.attach(5);
  Serial.begin(9600); //启动串口通讯,传输波特率9600
  Serial.println("Please input serial data.");
}
 
void loop() {          // 检查串口缓存是否有数据等待传输 
  
  if ( Serial.available()>0 ) {   
    
    int pos = Serial.parseInt();   // 解析串口数据中的整数信息并赋值给变量pos
    if(pos){
      dataIndex++;       // 处理数据序列号并通过串口监视器显示
      Serial.print("dataIndex = ");
      Serial.print(dataIndex);
      Serial.print(" , ");  
       
      Serial.print("Set servo position: ");
      Serial.println(pos);           // 通过串口监视器显示变量pos数值
      myServo.write(pos);             // 使用pos变量数值设置伺服电机
      delay(1000);
     }
    
  }
}

2.2 串口输入控制多个电机

#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;
    }
  }
}

2.3 一维数组控制多个电机

#include <Servo.h>
 
Servo base, fArm, rArm, claw;
 
int data[5] = {0, 45, 90, 135, 180};
 
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'
}
 
void loop() { 
  for (int i = 0; i <= 4; i++){
    base.write(data[i]);
    delay(100);
    rArm.write(data[i]);
    delay(100);
    fArm.write(data[i]);
    delay(100);
    claw.write(data[i]);
    delay(100);
  }
  for (int i = 4; i >= 0; i--){
    base.write(data[i]);
    delay(100);
    rArm.write(data[i]);
    delay(100);
    fArm.write(data[i]);
    delay(100);
    claw.write(data[i]);
    delay(100);
  }
}

2.3二维组控制多个电机

#include <Servo.h>
 
Servo base, fArm, rArm, claw;
 
int data2dArray[4][5] = {  //建立二维数组用以控制四台舵机
  {0,   45,   90,   135,  180},
  {45,  90,   135,  90,   45},
  {135, 90,   45,   90,   135},
  {180, 135,  90,   45,   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'
}
 
void loop() { 
  for (int i = 0; i <= 4; i++){  
    base.write(data2dArray[0][i]);  //base舵机对应data2dArray数组中第1“行”元素
    delay(100);                     
    rArm.write(data2dArray[1][i]);  //rArm舵机对应data2dArray数组中第2“行”元素
    delay(100);                     
    fArm.write(data2dArray[2][i]);  //fArm舵机对应data2dArray数组中第3“行”元素
    delay(100);                     
    claw.write(data2dArray[3][i]);  //claw舵机对应data2dArray数组中第4“行”元素
    delay(500);                     
  }
  for (int i = 4; i >= 0; i--){
    base.write(data2dArray[0][i]);  //base舵机对应data2dArray数组中第1“行”元素
    delay(100);                     
    rArm.write(data2dArray[1][i]);  //rArm舵机对应data2dArray数组中第2“行”元素
    delay(100);                     
    fArm.write(data2dArray[2][i]);  //fArm舵机对应data2dArray数组中第3“行”元素
    delay(100);                     
    claw.write(data2dArray[3][i]);  //claw舵机对应data2dArray数组中第4“行”元素
    delay(500);  
  }
}

 

 3.esp8266和python控制舵机

源自于8.3.通过网页文本框控制ESP8266开发板的PWM引脚


#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WebServer.h>
#include <FS.h>  
#include <Servo.h>
 
Servo myServo;  

ESP8266WiFiMulti wifiMulti;         // 建立ESP8266WiFiMulti对象
 
ESP8266WebServer esp8266_server(80);// 建立ESP8266WebServer对象,该对象用于响应HTTP请求。监听端口(80)

void setup(void){
  myServo.attach(14); //D5
  Serial.begin(9600);        
  Serial.println("");
  
  pinMode(LED_BUILTIN, OUTPUT);      // 初始化NodeMCU控制板载LED引脚为OUTPUT

  wifiMulti.addAP("yang1234", "y123456789"); // 将需要连接的一系列WiFi ID和密码输入这里
  wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); // ESP8266-NodeMCU再启动后会扫描当前网络
  wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); // 环境查找是否有这里列出的WiFi ID。如果有
  Serial.println("Connecting ...");                            // 则尝试使用此处存储的密码进行连接。
  
  int i = 0;  
  while (wifiMulti.run() != WL_CONNECTED) { // 尝试进行wifi连接。
    delay(1000);
    Serial.print(i++); Serial.print(' ');
  }
  
  // WiFi连接成功后将通过串口监视器输出连接成功信息 
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());              // 通过串口监视器输出连接的WiFi名称
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());           // 通过串口监视器输出ESP8266-NodeMCU的IP

  if(SPIFFS.begin()){                       // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  } else {
    Serial.println("SPIFFS Failed to Start.");
  }                      
                 
  //初始化网络服务器
  esp8266_server.on("/LED-Control", handleLEDControl);   
  esp8266_server.onNotFound(handleUserRequest); // 处理其它网络请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void){
  esp8266_server.handleClient();  //处理网络请求
}                                
                                                                         
void handleLEDControl(){
  // 从浏览器发送的信息中获取PWM控制数值(字符串格式)
  String ledPwm = esp8266_server.arg("ledPwm"); 

  // 将字符串格式的PWM控制数值转换为整数
  int ledPwmVal = ledPwm.toInt();

  // 实施引脚PWM设置
  myServo.write(ledPwmVal);             // 使用pos变量数值设置伺服电机
//  analogWrite(LED_BUILTIN, ledPwmVal);

  // 建立基本网页信息显示当前数值以及返回链接
  String httpBody = "Led PWM: " + ledPwm + "<p><a href=\"/LED.html\"><-LED Page</a></p>";           
  esp8266_server.send(200, "text/html", httpBody);
}

// 处理用户浏览器的HTTP访问
void handleUserRequest() {         
     
  // 获取用户请求资源(Request Resource)
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);
  
  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源,则回复404 (Not Found)
  if (!fileReadOK){                                                 
    esp8266_server.send(404, "text/plain", "404 Not Found"); 
  }
}

bool handleFileRead(String resource) {            //处理浏览器HTTP访问

  if (resource.endsWith("/")) {                   // 如果访问地址以"/"为结尾
    resource = "/index.html";                     // 则将访问地址修改为/index.html便于SPIFFS访问
  } 
  
  String contentType = getContentType(resource);  // 获取文件类型
  
  if (SPIFFS.exists(resource)) {                     // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");          // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType);// 并且将该文件返回给浏览器
    file.close();                                // 并且关闭文件
    return true;                                 // 返回true
  }
  return false;                                  // 如果文件未找到,则返回false
}

// 获取文件类型
String getContentType(String filename){
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

python脚本

import requests
role = 178
response = requests.get("http://192.168.31.249/LED-Control?ledPwm=%s" % role)
print(response.text)

 

4.HTS-16L总线舵机

BigClaw爪子(86mm)

产品名称 控制方式 重量 扭力 电源范围 特点
LDX-335MG PWM 64g 20kg.cm 6-8.4V 堵转保护、过温保护、金属齿轮、数字舵机、电压/位置/温度反馈、串口控制
HTS-16L PWM 60g 16kg.cm 6-8.4V 角度回读、堵转保护、过温保护、金属齿轮、总线舵机