arduino确定舵机角度

2019-10-15 21:16:06 fanxiaoduo1 阅读数 367

随着Arduino开发板的普及,许多朋友希望能够自己制作基于MPU6050的控制系统,但由于缺乏专业知识而难以上手。此外,MPU6050的数据是有较大噪音的,若不进行滤波会对整个控制系统的精准确带来严重影响。
MPU6050芯片内自带了一个数据处理子模块DMP,已经内置了滤波算法,在许多应用中使用DMP输出的数据已经能够很好的满足要求。关于如何获取DMP的输出数据,我将在以后的文章中介绍。本文将直接面对原始测量数据,从连线、芯片通信开始一步一步教你如何利用Arduino获取MPU6050的数据并进行卡尔曼滤波,最终获得稳定的系统运动状态。一、应用:
运动感测游戏
现实增强、电子稳像、光学稳像、行人导航器、“零触控”手势用户接口、姿势快捷方式
下面可以看一下以下几个图片,这样你也许会了解一些!

第一张是MPU6000与MPU6050芯片的比较!


第二张是MPU6000与MPU6050芯片的最小驱动电路的连接!

MPU-6050的通信
MPU6050的数据接口用的是I2C总线协议,因此我们需要Wire程序库的帮助来实现Arduino与MPU6050之间的通信。请先确定是否安装Wire库,Wire库的官方文档(http://www.arduino.cc/en/Reference/Wire)
这是Arduino uno与mpu6050接线图(紫色线为中断线,可不接)SDA接口对应的是A4引脚,SCL对应的是A5引脚。
MEGA 2560开发板上20(SDA)引脚21(SCL)与mpu6050相对应的引脚对接即可
MPU6050需要5V的电源,可由UNO板直接供电。

二、我采用的是数字舵机DS3115 DS3109 数码舵机 反应灵敏,行程大,零盲区。绝非模拟 , 我们已经用4PL数码模式亲自使用测试过。
型号 S3115MG 提供给机器人使用
重量:60g
尺寸:40*20*40.5mm
速度:15KG 0.16sec/60° 4.8-7.2V (工作电压)
堵转扭矩: 15kg/cm 4.8-7.2V
工作电压:4.8-7.2V
工作电流:>600mA
线长:32cm
与Futaba,JR,SANWA,Hitec 等遥控系统兼容.
控制特性
控制方式:改变脉冲宽度
工作频率:50-330Hz
可控角度:180°(脉宽在500-2500us可满范围变化时)
中立位置:1500us
脉宽范围:500-2500us
死区宽度:3us
数字(数码)舵机和模拟舵机的区别


字舵机(Digital Servo)和模拟舵机(Analog
Servo)在基本的机械结构方面是完全一样的,主要由马达、减速齿轮、控制电路等组成,而数字舵机和模拟舵机的最大区别则体现在控制电路上,数字舵机的
控制电路比模拟舵机的多了微处理器和晶振。不要小看这一点改变,它对提高舵机的性能有着决定性的影响。

三、实现代码
以下代码在Arduino软件1.6.9版本中编译、烧写以及测试通过[code]
#include<Servo.h>
Servo analogservo;

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"

MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;
//int value;//定义一个整形变量用于存放读取到的信号值

int16_t value;//定义一个整形变量用于存放读取到的信号值

bool blinkState = false;
void setup() {
      Wire.begin();
      Serial.begin(38400);
      Serial.println("Initializing I2C devices...");
      accelgyro.initialize();
      Serial.println("Testing device connections...");
      Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
      analogservo.attach(7);//舵机连接在7号脚

}
void loop() {
      accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
      Serial.print("a/g:\t");
      Serial.print(gx/131);   
      Serial.print("\t");    

      value=91+gx/131;  
      Serial.println(value);  

      analogservo.write(value);
      blinkState = !blinkState;
}试验结果:只是利用一个x轴的加速度值

2020-01-10 14:58:18 haigear 阅读数 1759

舵机在人工智能领域使用相当广泛,尤其是涉及到各种精确运动转向的控制中几乎都有它的身影。在我们的雷达扫描案例中就必须使用到舵机(当然,伺服电机也是可以的,步进电机由于没有角度位置传感器一般不使用在这种精确角度控制的场合)。

不论是伺服电机还是舵机,都是有角度传感器的,舵机中比伺服电机中多了一个减速齿轮而已增加其扭矩,以便使用在负重运动的关节上,其余基本一样,也就是说使用上基本没有什么差别,他们都是靠脉冲宽度调制(PWM)来驱动的。

首先我们看看,我们能买到的最便宜的舵机是什么样子吧,这里我们用的是SG90(SG90有两种一种是SG90A一类是SG90D,分别是模拟和数字类型的,我这里使用模拟量的SG90A),转动角度为(090度或者0180)。如果要满足我们前面雷达扫描的360度的扫描可以购买360度的舵机(如MG945/946、995/996都可以,伺服电机也很好,就是贵了些)。
下图为SG90
在这里插入图片描述
下图为MG996/995/945/946
在这里插入图片描述

三根线:橙色为正极,棕色为负极,黄色为信号线
在这里插入图片描述
我们必须首先了解一下什么是PWM?

PWM是Pulse-width modulation的缩写,我们可以简单的翻译为脉冲宽度调制,或者脉冲宽度控制。那么这个东东是干什么用的呢,实际可以很简单的理解,就是通过将能量切片后得到的宽度占比来控制单位时间内输出能量的大小的方法。切片的宽度越小,输出的能量大小则越小,电机啊,灯泡等单位时间内得到的能量就越小,转速及亮度就越小,举个栗子,在电流不变的情况下,我们将输出的脉冲电压(如5V电压)切割为原来一半的宽度,并每间隔一个就拿掉它,那么就只剩下原来脉冲波的一半的宽度了,那么输出的总能量也就是以前的一半了,相当如2.5V。我们可以从下图来尝试理解:
在这里插入图片描述

了解了PWM后,我们就必须了解如何获得不同的脉冲宽度,尤其是在arduino中如何获得不同的脉冲宽度。

既然,我们已经知道,不同的脉冲宽度可以通过持续拉高或者拉低某个管脚的电平来实现,那么代码就很容易实现了。我们看看最简单的代码实现:

学会了如何使舵机工作起来后,接下来我们就要对它的精准度进行测试了。
我们知道,在arduino中或者是51单片机程序中使用舵机是需要先加载驱动类库的,如果没有这些类库,电机基本无法正常驱动的。当然,即使有驱动库,有很多时候舵机也可能不会按照我们设定的方式转动。
所以才有了我下面的这段自编写的舵机测试代码。

ardunio端代码如下:

int srvPin = 9; //数字接口9连接舵机信号线
int Angle;
int pWidth;
char val;
                   
void setup(){
    pinMode(srvPin,OUTPUT);
    Serial.begin(9600);
    Serial.println("--");
}
void loop()
{
  turnAround(90);
}

//转动函数
void turnAround(int pin,float agl)
{
   for(int i = 0;i<=18;i++)
   {        
      angleChange(pin,agl);
      delay(20);
   }     
}

//脉冲函数
void angleChange(int pin ,float angle)
{
    //500高电平毫秒为0度
    pWidth =500+map(angle,180,0,1800,0);// 
    digitalWrite(pin,HIGH); //舵机电平升高
    delayMicroseconds(pWidth);//延时脉宽值的微妙数
    digitalWrite(pin,LOW); //拉低电平
}

经过测试电机要旋转18次才能旋转到指定的角度。

1、对于板载电压的测试
还有一点,arduino uno的板子,很多时候供电达不到,舵机也不会转动,会导致串口通讯中断,不能通过指令来转动。而且在脱机转动的时候,arduino板上的指示灯会随着转动变暗。

2、脉冲宽度的测试
经过测试为13.9ms转动1度,与官方给出的2.5秒转动180度基本吻合。一旦脉冲宽度达到2500后超过300都按照2500来计算,或者叫做这300叫做冗余部分,超过2800后就开始这算了,自动折算为2800-2500,那么转动角度就是300/2500

3、转动角度测试
我对10个SG90进行了测试,没有一个会按照脉冲2500来转动180度,都会存在接近30度的多于角度,也就是每转动30度就会有5度的余量差。对于转动180度来说最终我们调整脉冲宽度为2100时基本转动角度符合要求了,但对于转动90度来说确有不足90了。
所以最终,我们决定将脉冲宽度的映射做一个变化处理,,这也就是angleChange函数中第一行使用map的原因。

我们通过测试,发现在0到20度内的角度无法给出转动动作。所以感觉这种舵机基本不能用于小角度的控制。当然,从大角度回转到小角度20度以内也会产生很大的误差,舵机会转动到0度附近。

每个舵机实际都需要调试,脉冲宽度为0的时候,电机也是为转动到某个角度的,而且转动到某个极限角度,在这个极限下,直到某个脉冲宽度下,都被视为0度,所以我们在调试舵机的时候必须给定一个0度参考脉冲宽度,也就是说,这个脉冲款都就是0度,在这个的基础上增加脉冲宽度是有转动动作发生的。

也就是说,我们给出了列入200的脉冲宽度,虽然舵机转动到了某个角度,但我们试图给它增加200的脉冲令其转动是不能成功的,它可能还在原地。也就是说,500内的脉冲区域其实都是舵机的转动死角区域,或者说非响应区,跟没有发指令一样,最多电机响动但不转动,而且进入死区后舵机可能在接收正常脉冲后还会一时难以恢复正常转动。

理论上2500毫秒是可以达到180度的转动,但实际也需要根据不同的舵机的位置传感器来确定,有的脉冲宽度2300就到了180度。这是我们必须引起注意的。

舵机的转速测试
舵机的转速慢,给定脉冲后它会朝着目标角度转去,位置传感器会告知电机是否到达了目标位置,如果没有到达那就继续转,一直到到达则不再转动。

2015-07-29 10:46:43 ling3ye 阅读数 23114

接上篇  光敏电阻实验   

 

 

要做向日葵式的太阳能收集器,除了找到光线外,还需要控制方向的部件,这里选择使用舵机控制方向,本实验室是用的是9克舵机。

舵机一般都是有可控制范围的,标准舵机是90度,也有小于90度的也有360度的舵机,本实验是180度的舵机。

这次实验除了实验了舵机的使用,还涉及到了串口的数据读取与发送。

 

1接线方法

PS:板子上数字接口,有些数字旁边有个~,有些没有,~代表有PWN,板子上也会有说明,可以留意一下。

 

2程序

程序打包下载地址:https://u16460183.ctfile.com/fs/16460183-295173181

#include <Servo.h> //引入lib

Servo myservo;  // 创建一个伺服电机对象

char inByte = 0; //串口接收的数据
int angle = 0;  //角度值
String temp = "";//临时字符变量,又或者说是缓存用的吧

void setup() 
{
  myservo.attach(9);    //定义舵机的引脚为9,舵机只能是10,或者9引脚
  Serial.begin(9600);  //设置波特率
}


void loop() 
{
  while (Serial.available() > 0) //判断串口是否有数据
  {
    inByte = Serial.read();//读取数据,串口一次只能读1个字符
    temp += inByte;//把读到的字符存进临时变量里面缓存,
                   //再继续判断串口还有没有数据,知道把所有数据都读取出来
   }

   if(temp != "")   //判断临时变量是否为空
   {
    angle = temp.toInt();    //把变量字符串类型转成整型
    Serial.println(angle);  //输出数据到串口上,以便观察
   }
  temp = "";//请看临时变量
  myservo.write(angle);  //控制舵机转动相应的角度。
  delay(100);//延时100毫秒
}

 

 

 

 

 

接好线上电烧好程序

 

打开串口,输入0-180的数值,记得是数值哦,

因为程序没有做数据验证如果输入其他会。。。。。。大家可以自己试试看。

正常输入数值,舵机就会转动相应的角度。

 

 

2014-11-03 14:57:25 wstcft 阅读数 2161
DIY

DIYer修炼:舵机知识扫盲

gunpole 发表于  2011-01-17 08:18
http://www.guokr.com/gkimage/p3/0q/3r/p30q3r.png
DIYer: Tod E. Kurt
GEEK指数: ★★★☆☆
 

1   简介

舵机控制的机器人

● 我猜你肯定在机器人和电动玩具中见到过这个小东西,至少也听到过它转起来时那与众不同的“吱吱吱”的叫声。对,它就是遥控舵机,常用在机器人技术、电影效果制作和木偶控制当中,不过让人大跌眼镜的是,它竟是为控制玩具汽车和飞机才设计的。
● 舵机的旋转不像普通电机那样只是古板的转圈圈,它可以根据你的指令旋转到0至180度之间的任意角度然后精准的停下来。如果你想让某个东西按你的想法运动,舵机可是个不错的选择,它控制方便、最易实现,而且种类繁多,总能有一款适合你呦。
● 用不着太复杂的改动,舵机就可摇身一变成为一个高性能的、数字控制的、并且可调速的齿轮电机。在这篇文章中,我会介绍舵机使用的的一些基础知识以及怎样制作一个连续运转舵机。
 

2   舵机的结构和原理

http://www.guokr.com/gkimage/uz/vm/cg/uzvmcg.png

A.标准舵机图解

● 遥控舵机(或简称舵机)是个糅合了多项技术的科技结晶体,它由直流电机、减速齿轮组、传感器和控制电路组成,是一套自动控制装置,神马叫自动控制呢?所谓自动控制就是用一个闭环反馈控制回路不断校正输出的偏差,使系统的输出保持恒定。我们在生活中常见的恒温加热系统就是自动控制装置的一个范例,其利用温度传感器检测温度,将温度作为反馈量,利用加热元件提输出,当温度低于设定值时,加热器启动,温度达到设定值时,加热器关闭,这样不就使温度始终保持恒定了吗。
 
http://www.guokr.com/gkimage/66/lj/qs/66ljqs.png

B.闭环反馈控制

● 对于舵机而言呢,位置检测器是它的输入传感器,舵机转动的位置一变,位置检测器的电阻值就会跟着变。通过控制电路读取该电阻值的大小,就能根据阻值适当调整电机的速度和方向,使电机向指定角度旋转。图A显示的是一个标准舵机的部件分解图。图B显示的是舵机闭环反馈控制的工作过程。
 

3   选择舵机

http://www.guokr.com/gkimage/sg/xl/5e/sgxl5e.png

C.大扭力/微型/标准舵机

● 舵机的形状和大小多到让人眼花缭乱,但大致可以如图C所示分类。最右边身材不错的是常见的标准舵机,中间两个小不点是体积最小的微型舵机,左边的魁梧的那个是体积最大的大扭力舵机。它们都是同样的三线控制,因此你可以根据需求换个大个的或小个的。
● 除了大小和重量,舵机还有两个主要的性能指标:扭力和转速,这两个指标由齿轮组和电机所决定。扭力,通俗讲就是舵机有多大的劲儿。在5V的电压下,标准舵机的扭力是5.5千克/厘米(75盎司/英寸),转速很容易理解,就是指从一个位置转到另一个位置要多长时间。在5V电压下,舵机标准转度是0.2秒移动60度。总之,和我们人一样,舵机的个子越大,转的就越慢但也越有劲儿。
● 赶快想好你要做的东西,让我们开始动手吧。确定做什么之后,选择哪种大小的舵机(标准型、微型、绞盘型)就是小case了,你可以绅士般的从中选个最便宜的。在这个项目中,我选的就是微型系列的HexTronik公司生产的HXT500型舵机,额定数值是扭力0.8千克,转速0.10秒,只花不到4美元就搞定了。
 

4   舵机的支架和连接装置

http://www.guokr.com/gkimage/0k/en/lk/0kenlk.png

D.多种舵盘

● 想在你的项目中用上舵机,就要满足两个条件:一是需要个能把舵机固定到基座上的支架,二是得有个能将驱动轴和物体连在一起的连接装置。支架一般舵机上就有,而且带有拧螺丝用的安装孔。如果你仅仅是测试的话,用点儿热熔胶或者双面泡沫胶带就能轻松的固定住舵机。
● 怎样连接驱动轴呢,你会发现舵机都附带了一些有孔的小东西,这就是舵盘,它可以套在驱动轴,臂上打上了些小孔。你只要用连接棒或者线把物体连到孔上,就可以将舵机的旋转运动变成物体的直线运动了,当然了,选用不同的舵盘或固定孔就能产生不同的运动啦。
● 图示的是几种不同的舵盘。前面4个白色的是舵机附带的舵盘,右边四个是用激光切割机切割塑料得到的DIY舵盘。最右边的2个是舵盘和支架的组合,如果你想实现两个舵机的组合运动,把这个舵盘的支架固定到另一个舵机的支架上就OK了。
 
http://www.guokr.com/gkimage/ki/9i/zy/ki9izy.png

E.普通舵盘设计

 
http://www.guokr.com/gkimage/y1/er/36/y1er36.png

F.其他舵盘

● 制作普通舵盘对于童鞋们来说是比较容易的,先用矢量作图软件画一个多边形,这个多边形的半径和顶点数都要和舵机驱动轴匹配,这样它就能连接到驱动轴上了,其他种类的也是这样画出来的。
 

5   如何控制舵机

http://www.guokr.com/gkimage/3o/kj/dd/3okjdd.png

G.3线接口

● 像图所示那样,舵机有一个三线的接口。黑色(或棕色)的线是接地线,红线接+5V电压,黄线(或是白色或橙色)接控制信号端。
 
http://www.guokr.com/gkimage/ey/l5/oa/eyl5oa.png

H.控制信号

● 控制信号(如图H)是一种脉宽调制(PWM)信号,凡是微控制器能轻松的产生这种信号。在此文中,我用的是常用的Arduino开发环境下的微控制器。
● 脉冲的高电平持续1到2毫秒(ms),也就是1000到2000微秒(µs)。在1000µs时,舵机左满舵。在2000µs时,右满舵。不过你可以通过调整脉宽来实现更大或者更小范围内的运动。
● 控制脉冲的低电平持续20毫秒。每经过20毫秒(50次每秒),就要再次跳变为高电平,否则舵机就可能罢工,难以保持稳定。不过你要是想让它一瘸一拐的跳舞,倒可以采取这种方法。
 
http://www.guokr.com/gkimage/gw/oy/b7/gwoyb7.png

这是一个完整的Arduino设计程序,在这个程序下,舵机始终在正中间位置,控制起来很容易

 
http://www.guokr.com/gkimage/qs/ej/nh/qsejnh.png

I.舵机连接Arduino实验板

● 红色和黑色的线分别接到Arduino开发板的5V电源脚和接地脚上。控制线接到Arduino开发板的数字输入/输出脚9脚上。
● 用Arduino控制舵机也有不太给力的地方,就是Arduino程序把绝大部分时间都浪费在等待延迟命令上,不过童鞋们暂时不要失望,Arduino中内置有舵机函数,你可以用它内置的计数器来同时控制两个舵机(分别在9脚和10脚),是不是又豁然开朗了,这样我们不就能把节省下的编程代码干别的事情了吗。
 
http://www.guokr.com/gkimage/cy/yy/v7/cyyyv7.png

这是一个调用了舵机函数的程序

 

6   舵机应用:云台网络摄像头

http://www.guokr.com/gkimage/b8/wu/43/b8wu43.png

J.舵机控制的云台网络摄像头

● 看了这么多内容了,是不是有点迫不及待练练手的冲动,那就先来个简单的,材料就是下面这些,两个舵机、一个Arduino板、一个用来装摄像头的可转动基座。先用热胶把第一个舵机的舵盘固定到摄像头的底部,然后把第二个舵机固定到基座上,同时把它的舵盘固定到第一个舵机的一侧,最后把舵盘套到各自舵机上,哇塞,一个云台网络摄像头就这样诞生了。
● 图中是一个纯手工打造的云台网络摄像机,它用的是OpenWrt Linux系统的华硕wi-fi路由器。
● 网络摄像头和Arduino控制板都是用USB集线器连接到路由器上的。
 
http://www.guokr.com/gkimage/6n/ut/ug/6nutug.png

通过Arduino的USB口同时控制两个舵机的程序

● 大致的流程是这样滴,当串口上有两个字节到来时,程序开始工作,赋给第一个字节0-180的值,让它调节摇摆舵机(调左右),同样赋给第二个字节0-180的值,让它调节倾斜舵机(调上下)。
 

7   如何DIY连续旋转的舵机

http://www.guokr.com/gkimage/jn/y3/zp/jny3zp.png

K.舵机的内部“解剖”结构

● 任何舵机都能变成一个双向、可调速的降速齿轮电机。通常情况下,需要驱动芯片和其他一些零件才能控制电机的转速和方向,这些部件舵机中都会附带,所以要想得到一个用到机器人上的数控连续旋转舵机,最简单也最便宜的的方法就是自己动手改造一个,哈哈,考验动手能力的时候又来了。
 
http://www.guokr.com/gkimage/uw/k9/qp/uwk9qp.png

L.拿掉金属挡板

● 需要改动的是部分的电路模块和机械模块,电路模块中,我们要找两个阻值相同的电阻来充当电位计,机械模块中,则要去掉防止电机过速的挡板。
 
http://www.guokr.com/gkimage/r5/21/uw/r521uw.png

M.卸下塑料挡板

● 下面我们就开始吧,首先,卸开舵机外壳,HTX500舵机的外壳由3个塑料部分扣在一起。你可以用个小一字改锥或是类似的片状工具把他撬开,然后从轴上取下齿轮组,(记得标记好各个小齿轮的位置哦),再从下面小心的取出舵机的电路板。
● 舵机上有两个机械制动挡板,用尖嘴钳卸下驱动轴基座上的金属挡板(图L),用斜嘴钳卸下外壳顶部的塑料挡板(图M)。
 
http://www.guokr.com/gkimage/kq/d5/5w/kqd55w.png

N.焊上电阻

 
http://www.guokr.com/gkimage/z7/ji/vz/z7jivz.png

O.缠上胶带

● 用两个阻值相加约5 kΩ的电阻来替代5 kΩ的电位计,实际制作中,选一对2.2kΩ的电阻就能满足要求了。把电位计上的3根线焊下来,像图N那样焊到电阻上。再把这个重新组装成的家伙用绝缘胶带或是绝缘管缠好(图O),最后再和电路板一起重新塞进舵机外壳中,扣好外壳,一个改造好的舵机就呈现在我们面前了。
● 手工制作阶段到此就结束了,但是现在还能高兴的太早,因为只有找到基准点才能算是大功告成。在理想条件下,如果两个电阻完全相同,舵机就能精确的停到90度的位置上。不过呢,理想和现实总是会差那么一点点,因此舵机就没像理想中那样么精确。为了使舵机控制更精确,我们要找到一个基准点,方法是把上面编的程序灌进电路中,通过实验来看舵机究竟停在哪个角度,这个角度每个舵机都不相同,所以得出结果后要记录下来。
● 我们业余爱好者常用的舵机一般是用电位计来检测驱动轴转动到的角度,而用在工业机器人、电脑数控机床等大型系统中的舵机一般则要用旋转编码器来确定位置。光学旋转编码器的原理是这样的,把一个带有窄缝的圆盘固定在转轴上,然后用一个LED灯和一个光敏元件来记录光通过窄缝照到光敏器件上的次数来计算当前旋转到的位置。其实生活中这种技术也很常见,我们每天都要用的光电鼠标就是用的这个原理制作成的。
注:如果你不想撬开你心爱的舵机,Parallax公司(BASIC Stamp微处理器的制造商)有一款即用型,标准尺寸的连续转动舵机可供你使用。
 

8   连续旋转舵机的应用:5分钟的绘图机器人

http://www.guokr.com/gkimage/0c/ce/g8/0cceg8.png
  • P.安装好的绘图机器人*
● 想做个会画画的的机器人吗,那就去找两个连续旋转舵机来吧,我们这就开始。图O这个绘图机器人中包含了舵机两个, 9V电池,面包板, Arduino电路板,三福记号笔各一个,外加一对塑料轮子。
● 它的电路和云台摄像头一样,我们直接拿来用,而且它的部件都可以用热胶粘到一起。关于轮子的选择,更是简单,只要是直径在1到3英寸的圆东西都能用,比如塑料瓶盖之类的。为了减小摩擦,增大牵引力,我们在车轮上缠上塑料胶带。
● 这样组装阶段就完成了。接下来就是程序了,它的程序用一个包含基准点的变量来制动舵机,这个基准点我们上面已经通过实验测出(你的基准点可能不同)。程序的控制流程为,先让一个舵机朝一个方向运动一段时间,然后换成另一个舵机转动,这样就能得到一个螺线形的图画了。
● 代码在此:
#include
Servo servoL;
Servo servoR;
int servoLZero = 83; // experimentally found to stop L motor
int servoRZero = 91; // experimentally found to stop R motor
boolean turnleft = false;
void setup() {
servoL.attach(9);
servoR.attach(10);
servoL.write(servoLZero); // start out not moving
servoR.write(servoRZero); // start out not moving
}
void loop() {
turnleft = !turnleft;
if( turnleft ) {
servoL.write( servoLZero - 10 );
servoR.write( servoRZero );
delay(1000);
} else {
servoL.write( servoLZero );
servoR.write( servoRZero + 10 );
delay(4000); // turn more one way than the other
}
}
 
http://www.guokr.com/gkimage/q6/lx/l9/q6lxl9.png

Q.运动中的绘图机器人

● 注意:永久记号笔画的痕迹不好清除,童鞋们千万小心哈,最好让绘图机器人在硬纸板或其他不透水的纸的画画,或者索性换成支水溶性的记号笔。
 

资料来源

翻译: gunpole
编辑: Luna3.0

果壳DIY站QQ群:132647923

果壳DIY站微博: http://t.sina.com.cn/guokrdiy

2018-08-31 02:42:01 qq_42807924 阅读数 22192

16路12位PWM信号发生器 PCA 9685

节省主机资源,值得拥有。此舵机驱动板使用PCA9685芯片,是16通道12bit PWM舵机驱动,用2个引脚通过I2C就可以驱动16个舵机。
这里写图片描述
强大如斯!
这里写图片描述

先对单个舵机尝试一下,了解一下PWM

这里写图片描述
20ms周期 = 频率为50Hz
这里写图片描述
这里写图片描述

单个舵机例程1:

非常简单的舵机例子,实现效果是使得电机转动:

#include <Servo.h>  
#define PIN_SERVO 10
Servo myservo;  
void setup()  
{  
  myservo.attach(PIN_SERVO);  
}  
void loop()  
{  
  myservo.write(0);  
  delay(1000);  
  myservo.write(80);  
  delay(1000);  
  myservo.write(160);  
  delay(1000);  
  myservo.write(80);  
  delay(1000);  
  myservo.write(0);  
  delay(1000);  
} 

单个舵机例程2:

#include <Servo.h>  
#define PIN_SERVO 9
int i=0;
Servo myservo;  
void setup()  
{  
  myservo.attach(PIN_SERVO);  
}  
void loop()  
{  
for(i=0;i<160;i++)
{
  myservo.write(i);  
  delay(30);
}
for(i=160;i>0;i--)
{
  myservo.write(i);  
  delay(30);
}
delay(1000);
} 


单个舵机使用板上的I/O口就可以,可是舵机多了呢?
来学习PCA 9685

主要参数以及引脚定义:

在这里插入图片描述

  1. 电压:舵机供电5-7v,接受高一点的电压。

大多数的舵机设计电压都是在5~6V,尤其在多个舵机同时运行时,跟需要有大功率的电源供电。如果直接使用Arduino
5V引脚直接为舵机供电,会出现一些难以预测的问题,所以我们建议你能有个合适的外部电源为驱动板供电。

  1. 逻辑电路电压:3-5V

  2. 通信接口:使用i2c通信,就是SCL、SDA引脚

7位的I2C地址为:0x40 + A5:A0,A5到A0如果不做任何处理的话是0,想要把哪一位置1就把那个引脚焊到一起。另外用i2cdetect检测出还有一个0x70地址一直存在,这是一个通用地址,可以给所有从机下达指令。

  1. OE反使能脚:这个引脚低电平使能,不接的话模块内部默认已经接地使能了,所以正常使用可以不接。

  2. 工作频率:40-1000HZ


接线图:

这里写图片描述

注意!!!下面例子需要用到外部库文件,如果你IDE没有<Adafruit_PWMServoDriver.h>,那么下载这个并放在安装路径的文档—arduino-libraries路径下面

16路舵机驱动板资料(内含模块级联说明):https://pan.baidu.com/s/1gfhFGDP
在这里插入图片描述


例子程序1

(有时间就简化一下,好像还不是最好的例子)
16路舵机同时转动。原理是定义脉宽最大和最小,通过改变0-15号舵机的脉宽大小实现角度转动

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  Servo test - this will drive 16 servos, one after the other
  这是我们的Adafruit 16通道PWM和伺服驱动器的一个例子,驱动16个伺服电机

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate, 2 pins are required to  
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4
  这些显示器使用I2C进行通信,需要2个引脚。
  接口。对于ARDUINO UNOS,这是SCL->模拟5,SDA - >模拟4

  ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// called this way, it uses the default address 0x40
////以这种方式调用,它使用默认地址0x40。
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
//也可以用不同的地址调用它

/* Depending on your servo make, the pulse width min and max may vary, you  want these to be as small/large as possible without hitting the hard stop
 for max range. You'll have to tweak them as necessary to match the servos you
have!*/
/*根据你的伺服制作,脉冲宽度最小和最大可能变化,你想要这些尽可能小大而不碰到
硬停止,对于最大范围。你必须调整它们以匹配你的伺服系统!*/
#define SERVOMIN  150 // this is the 'minimum' pulse length count (out of 4096)
//这是“最小”脉冲长度计数(在4096)中
#define SERVOMAX  600 // this is the 'maximum' pulse length count (out of 4096)
//这是“最大”脉冲长度计数(在4096中)

// our servo # counter
//uint8_t servonum = 0;

void setup() {
   Serial.begin(9600);
   Serial.println("16 channel Servo test!");

  pwm.begin();
   
   pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
   ////模拟伺服在60赫兹更新下运行
}

// you can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
//如果您想以秒为单位设置脉冲长度,则可以使用此函数。
//例如SET伺服脉冲(0,0.001)是一个1毫秒的脉冲宽度。它不是
void setServoPulse(uint8_t n, double pulse) {
   double pulselength;//精度浮点数
   
   pulselength = 1000000;   // 1,000,000 us per second 每秒100万
   pulselength /= 60;   // 60 Hz
   Serial.print(pulselength); Serial.println(" us per period"); 
   pulselength /= 4096;  // 12 bits of resolution 12位分辨率
   Serial.print(pulselength); Serial.println(" us per bit"); 
   pulse *= 1000;
   pulse /= pulselength;
   Serial.println(pulse);
   pwm.setPWM(n, 0, pulse);
}

void loop() {
   // Drive each servo one at a time
   //Serial.println(servonum);
   //每次驱动一个伺服驱动器
//串行打印(伺服);
   for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
     pwm.setPWM(0, 0, pulselen);
     pwm.setPWM(1, 0, pulselen);
     pwm.setPWM(2, 0, pulselen);
     pwm.setPWM(3, 0, pulselen);
     pwm.setPWM(4, 0, pulselen);
     pwm.setPWM(5, 0, pulselen);
     pwm.setPWM(6, 0, pulselen);
     pwm.setPWM(7, 0, pulselen);
     pwm.setPWM(8, 0, pulselen);
     pwm.setPWM(9, 0, pulselen);
     pwm.setPWM(10, 0, pulselen);
     pwm.setPWM(11, 0, pulselen);
     pwm.setPWM(12, 0, pulselen);
     pwm.setPWM(13, 0, pulselen);
     pwm.setPWM(14, 0, pulselen);

     pwm.setPWM(15, 0, pulselen);
   }
   delay(500);
   for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
     pwm.setPWM(0, 0, pulselen);
     pwm.setPWM(1, 0, pulselen);
     pwm.setPWM(2, 0, pulselen);
     pwm.setPWM(3, 0, pulselen);
     pwm.setPWM(4, 0, pulselen);
     pwm.setPWM(5, 0, pulselen);
     pwm.setPWM(6, 0, pulselen);
     pwm.setPWM(7, 0, pulselen);
     pwm.setPWM(8, 0, pulselen);
     pwm.setPWM(9, 0, pulselen);
     pwm.setPWM(10, 0, pulselen);
     pwm.setPWM(11, 0, pulselen);
     pwm.setPWM(12, 0, pulselen);
     pwm.setPWM(13, 0, pulselen);
     pwm.setPWM(14, 0, pulselen);

     pwm.setPWM(15, 0, pulselen);
   }
   delay(500);

}

例子程序2:

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
 
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
 
// our servo # counter
//uint8_t servonum = 0;
 
void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");
 
  pwm.begin();
  
  pwm.setPWMFreq(50);  // Analog servos run at ~50 Hz updates模拟伺服运行在50赫兹更新
}
 
void loop() {
  //setServoPulse(0, 0.001);
  //setServoPulseMS(1, 50);
  pwm.setPin(0,0,0);
  pwm.setPin(1,4096,0);
  pwm.setPin(2,(0.5/20.0)*4096,0);
}

IDE自带例程:

/*************************************************** 
  This is an example for our Adafruit 16-channel PWM & Servo driver
  PWM test - this will drive 16 PWMs in a 'wave'

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate, 2 pins are required to  
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
这是我们的AdfRuIT 16通道PWM和伺服驱动器的一个例子。
PWM测试-这将驱动16个波姆斯在“波”
今天在AdfRuIT商店挑选一个!
------HTTP://www. AdAfRuIT.COM/PROSTS/815
这些显示器使用I2C进行通信,需要2个引脚。
接口。对于ARDUINO UNOS,这是SCL->模拟5,SDA - >模拟4
ADAFRUIT投入时间和资源来提供这个开源代码,
请通过购买支持AdfRuIT和开源硬件
来自AdfRuIT的产品!
由Limor Fray/Lajayad撰写的AdfuRIT产业。
BSD许可证,以上所有文本必须包含在任何再分配中
***********************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
//以这种方式调用,它使用默认地址0x40。
// called this way, it uses the default address 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
//你也可以用不同的地址称呼它。
//ADAFRUITIGPWM伺服驱动器PWM=ADAFRUITIGPWM伺服驱动器(0x41);

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel PWM test!");

  // if you want to really speed stuff up, you can go into 'fast 400khz I2C' mode
  // some i2c devices dont like this so much so if you're sharing the bus, watch
  // out for this!
  //如果你真的想加快速度,你可以进入“快速400千赫I2C”模式。
//一些I2C设备不太喜欢这个,所以如果你在共享公共汽车,请注意。
//为了这个!

  pwm.begin();
  pwm.setPWMFreq(1600);  // This is the maximum PWM frequency这是最大PWM频率
    
  // save I2C bitrate
  uint8_t twbrbackup = TWBR;
  // must be changed after calling Wire.begin() (inside pwm.begin())
  //保存I2C比特率
//必须在调用Word.No.2之后更改(内部PWM(开始))
  TWBR = 12; // upgrade to 400KHz!升级到400千赫!
    
}

void loop() {
  // Drive each PWM in a 'wave'
  //在“波”中驱动每个PWM
  for (uint16_t i=0; i<4096; i += 8) { //i=i+8
    for (uint8_t pwmnum=0; pwmnum < 16; pwmnum++) {
      pwm.setPWM(pwmnum, 0, (i + (4096/16)*pwmnum) % 4096 ); //%求余数 x = 7 % 5; //x=2,余数为2,如果i=8,pwmnum=2,(8+256*2)=520,520%4096
    }
  }
}

Arduino的例子暂时没有找到很简洁的,OpenMv例子很简单易懂,欢迎围观我的Blog——【OpenMV学习笔记】 pca9685学习之用python尝试写代码:https://blog.csdn.net/qq_42807924/article/details/82354781
OpenMV控制单个PWM舵机:https://blog.csdn.net/qq_42807924/article/details/82563671

基础知识:

上面有出现uint8_t uint16_t,那它们是什么?其实很简单:

1字节 uint8_t //无符号整型
2字节 uint16_t

编程语言不扎实看一下字节定义:

    
    B就是Byte,也就是字节;b是bit的缩写,b就是bit,也就是比特位(bit)。B与b不同,注意区分,KB是千字节,Kb是千比特位。
    8bit(比特位)=1Byte(字节);
    1024Byte(字节)=1KB(千字节)1024KB(千字节)=1MB(兆字节);
    1MB(兆字节)=1024KB(千字节)=1024*1024B(字节)=1048576B(字节)1024MB=1GB;
    1024GB=1TB;

这里写图片描述
_t的意思到底表示什么?

它就是一个结构的标注,可以理解为type/typedef的缩写,表示它是通过typedef定义的,而不是其它数据类型
头文件内定义:
typedef signed char int8_t;
//无符号整型
typedef unsigned char uint8_t;
typedef int int16_t;
typedef unsigned int uint16_t;

进阶学习:

从例子中模仿,从库函数中掌握!

库文件:AdafruitPWMServoDriverLibrary
1.

setPWMFreq(freq)

eg: pwm.setPWMFreq(1000); // set the PWM frequency to the maximum value of 1000Hz
Description: 用来调节PWM频率,范围 freq:40-1000Hz

setPWM(channel, on, off)

Description
This function sets the start (on) and end (off) of the high segment of the PWM pulse on a
specific channel. You specify the ‘tick’ value between 0…4095 when the signal will turn on,
and when it will turn of. Channel indicates which of the 16 PWM outputs should be updated
with the new values.
Arguments
channel: The channel that should be updated with the new values (0…15)
on: The tick (between 0…4095) when the signal should transition from low to high
off:the tick (between 0…4095) when the signal should transition from high to low
Example
The following example will cause channel 15 to start low, go high around 25% into the pulse
(tick 1024 out of 4096), transition back to low 75% into the pulse (tick 3072), and remain low
for the last 25% of the pulse:
描述
该功能设置a上PWM脉冲高段的开始(on)和end(off)
特定渠道。 当信号打开时,指定0…4095之间的’tick’值,
什么时候会转。 通道指示应更新16个PWM输出中的哪一个
用新的价值观。
参数
channel:应使用新值更新的通道(0…15)
on:当信号从低电平变为高电平时的滴答(在0…4095之间)
off:当信号从高电平变为低电平时的滴答(在0…4095之间)

以下示例将导致通道15从低电平开始,在脉冲中高达25%左右
(在4096中打勾1024),转换回脉冲的低75%(勾选3072),并保持低位
对于最后25%的脉冲:
eg: setPWM(15, 1024, 3072);

4096这个数到底是什么?

The turn-on time of each LED driver output and the duty cycle of PWM can be controlled
independently using the LEDn_ON and LEDn_OFF registers.
There will be two 12-bit registers per LED output. These registers will be programmed by
the user. Both registers will hold a value from 0 to 4095. One 12-bit register will hold a
value for the ON time and the other 12-bit register will hold the value for the OFF time. The
ON and OFF times are compared with the value of a 12-bit counter that will be running
continuously from 0000h to 0FFFh (0 to 4095 decimal).
Update on ACK requires all 4 PWM channel registers to be loaded before outputs will
change on the last ACK.
The ON time, which is programmable, will be the time the LED output will be asserted and
the OFF time, which is also programmable, will be the time when the LED output will be
negated. In this way, the phase shift becomes completely programmable. The resolution
for the phase shift is 1⁄4096
4096 of the target frequency. Table 7 lists these registers.
The following two examples illustrate how to calculate values to be loaded into these
registers.
Example 1: (assumes that the LED0 output is used and
(delay time) + (PWM duty cycle)  100 %)
Delay time = 10 %; PWM duty cycle = 20 % (LED on time = 20 %; LED off time = 80 %).
Delay time = 10 % = 409.6 ~ 410 counts = 19Ah.
Since the counter starts at 0 and ends at 4095, we will subtract 1, so delay time = 199h
counts.
LED0_ON_H = 1h; LED0_ON_L = 99h (LED start turn on after this delay count to 409)
LED on time = 20 % = 819.2 ~ 819 counts.
LED off time = 4CCh (decimal 410 + 819  1 = 1228)
LED0_OFF_H = 4h; LED0_OFF_L = CCh (LED start turn off after this count to 1228)
这里写图片描述
PWM频率PRE_SCALE
硬件强制可以加载到PRE_SCALE寄存器中的最小值
在’3’。 PRE_SCALE寄存器定义输出调制的频率。该
预分频值由公式1中所示的公式确定:
(1)
其中更新速率是所需的输出调制频率。例如,对于
输出默认频率为200 Hz,振荡器时钟频率为25 MHz:
(2)
如果PRE_SCALE寄存器设置为“0x03h”,则最大PWM频率为1526 Hz。
如果PRE_SCALE寄存器设置为“0xFFh”,则最小PWM频率为24 Hz。
只有当MODE1寄存器的SLEEP位设置为时,才能设置PRE_SCALE寄存器
逻辑1.例1 :(假设使用了LED0输出和
(延迟时间)+(PWM占空比)100%)
延迟时间= 10%; PWM占空比= 20%(LED导通时间= 20%; LED关闭时间= 80%)。
延迟时间= 10%= 409.6~410计数= 19Ah。
由于计数器从0开始并在4095结束,我们将减去1,因此延迟时间= 199h
计数。
LED0_ON_H = 1h; LED0_ON_L = 99h(此延迟计数到之后LED开启亮起
409)
LED导通时间= 20%= 819.2~819计数。
LED关闭时间= 4CCh(十进制410 +8191= 1228)
LED0_OFF_H = 4h; LED0_OFF_L = CCh(此计数到1228后LED开始关闭)

这居然是最高阅读量的Blog,开始写的有点迷惑,今天抽点时间优化一下结构,后面会继续优化,博主也不是完全掌握,有任何疑问评论区见,大家共同学习,如果有帮到你,记得点赞噢!——2018年10月11日13点32分编辑

2019年1月19日,插播一波,如果感兴趣的童鞋们可以加入技术交流群~

在这里插入图片描述

完。

pca9685的舵机控制

阅读数 5313