mblock控制SG90舵机模块

【1.关于SG90舵机】

SG90舵机是Arduino中常用的一种舵机。这是一种模拟舵机,和数字舵机不同,模拟舵机需要持续发送控制脉冲,才能使舵机旋转到某个角度并保持。

Arduino中使用SG90舵机,常用方法是使用servo库。但是servo库使用了timer1定时器,和arduino产生pwm信号也使用了timer1定时器,因此使用servo库和使用pwm产生冲突。其中一个解决方法是把舵机的控制口接到一个非PWM口(如2号口),利用软件从2号口输出控制舵机的波形。

要控制SG90u舵机,需要持续不断给SG90发送周期为20ms的脉冲,单个脉冲周期中高电平的持续时间t决定了舵机的旋转角度。其中t为500微秒到2500微秒,对应着舵机旋转角度0到180度。并且高电平持续时间t和舵机旋转角度保持着线性对应关系。如2号口产生了高电平保持500微秒的脉冲,SG90舵机角度为0度,2号口产生了高电平保持2500微秒的脉冲,SG90舵机角度为180度,

【2.使用mblock产生舵机控制脉冲】

使用mblock自带的标准模块,产生控制SG90舵机的脉冲信号,如图1所示 
mblock控制SG90舵机模块_第1张图片
                                   图1
根据图1,产生了80个周期为20ms的脉冲,脉冲高电平的持续时间由angle决定。该模块产生的控制舵机旋转角度的精度不够。经过分析发现,这里使用的延时模块(等待x秒)由millis()函数产生,而millis函数的精度为ms级,因此不能产生精度为微秒级的延迟。所以导致产生的脉冲高电平持续时间不精确,进而造成控制舵机旋转角度不精确。

【3.自定义mblock模块,控制SG90舵机】

Arduino中有delayMicroseconds()函数,可以产生微秒级的延迟,但是mblock中并没有提供该函数相应的模块。决定自定义mblock扩展模块,使用delayMicroseconds()函数,产生精度为微秒级的舵机控制脉冲。

自定义的舵机控制模块一共使用了5个文件:Ext_yoyoba.s2e,demo.cpp,demo.h,myservo.c,myservo.h,内容分别如下:

ext_yoyoba.s2e文件内容:
 
  1. {    
  2.     "extensionName": "Ext_yoyoba",
  3.     "description": "Extention by YOYOBA",
  4.     "version": "1.1",
  5.     "author": "yoyoba([email protected])",
  6.     "homepage": "youhaidong.cn",
  7.     "sort":0,
  8.     "javascriptURL":"",
  9.       "firmware":"1.0",
  10.       "extensionPort":0,
  11.     "tags" : "makeblock",
  12.     "blockSpecs": [
  13.         [
  14.             "w",
  15.             "servo_init( %n )",
  16.             "servo_init",
  17.             "2",
  18.             {
  19.                 "setup":"",
  20.                 "inc":"#include \"demo.h\"",
  21.                 "def":"DemoClass demo; \n",
  22.                 "work":"demo.servo_init({0}); \n",
  23.                 "loop":""
  24.             }
  25.         ],
  26.         [
  27.             "w",
  28.             "servo_ctrl( %n )",
  29.             "servo_ctrl",
  30.             "90",
  31.             {
  32.                 "setup":"",
  33.                 "inc":"#include \"demo.h\"",
  34.                 "def":"DemoClass demo; \n",
  35.                 "work":"demo.servo_ctrl({0}); \n",
  36.                 "loop":""
  37.             }
  38.         ],
  39.     ],
  40.     "translators":{
  41.         "zh_CN":{
  42.                   "servo_init( %n )":"设置S90G舵机的I/O口( %n )",
  43.                   "servo_ctrl( %n )":"设置S90G舵机的角度( %n )"
  44.         }
  45.     }
  46. }
demo.cpp文件内容
 
  1. #include "demo.h"
  2. #include "myservo.h"
  3. DemoClass::DemoClass(){//构造函数
  4.     pinMode(13,OUTPUT);
  5. }
  6. DemoClass::~DemoClass()//析构函数
  7. {
  8. }
  9.  
  10. void DemoClass::servo_init(int pin)
  11. {
  12.     servo_pin=pin;
  13.     servo_init_t(servo_pin);
  14. }
  15.  
  16. void DemoClass::servo_ctrl(int arg)
  17. {
  18.     servo_arg=arg;
  19.     servopulse(servo_arg);
  20. }
demo.h文件内容:
 
  1. #ifndef demo_h
  2. #define demo_h
  3.  
  4. #include <Arduino.h>
  5. ///@brief Class for DemoClass
  6. class DemoClass
  7. {
  8.     public:
  9.     
  10.         DemoClass();
  11.         ~DemoClass();
  12.  
  13.         //S90G舵机使用的arduino I/O口;
  14.         void servo_init(int pin);
  15.  
  16.         //设置S90G舵机角度为arg(0~180)
  17.         void servo_ctrl(int arg);
  18.     private:
  19. };
myservo.c文件内容:
 
  1. #include <Arduino.h>
  2. #include "myservo.h"
  3.  
  4. int servo_pin;
  5. int servo_arg;
  6.  
  7. void servo_init_t(int pin)
  8. {
  9.     pinMode(pin,OUTPUT);
  10. }
  11.  
  12. void servopulse(int angle)
  13. {
  14.     int i=0;
  15.      int pulsewidth=(angle*11)+500; //将角度转化为500-2480微秒的脉宽值
  16.      for(;i<70;i++){//周期性发送70个脉冲,使得S90G舵机偏转一定角度
  17.          digitalWrite(servo_pin,HIGH); //将舵机接口电平至高
  18.          delayMicroseconds(pulsewidth); //延时脉宽值的微秒数
  19.          digitalWrite(servo_pin,LOW); //将舵机接口电平至低
  20.          delayMicroseconds(20000-pulsewidth);
  21.      }
  22. }
servo.h文件内容:
 
  1. #ifndef MYSERVO__H__
  2. #define MYSERVO__H__
  3.  
  4. #ifdef __cplusplus
  5. extern "C"
  6. {
  7. #endif//__cplusplus
  8.  
  9. extern int servo_pin;
  10. extern int servo_arg;
  11.  
  12. //初始化S90G舵机使用的arduino的I/O口pin    
  13. void servo_init_t(int pin);
  14. //设置s90G舵机的偏转角度angle(0~180)
  15. void servopulse(int angle);
  16.     
  17. #ifdef __cplusplus
  18. }
  19. #endif//__cplusplus
  20.  
  21. #endif
 

【4.实验结果】

在mblock中使用自定义的控制舵机的扩展模块,并编写测试程序,如图2所示,表明能较好的控制舵机的运行。 
mblock控制SG90舵机模块_第2张图片

            图2

mblock控制SG90舵机模块_第3张图片

图3 

【5.注意事项】
本程序中使用了很多全局变量,这些全局变量都定义在seg4_led.c文件中。
 

  1. // 全局变量k_num,h_num,d_num,g_num分别存放
  2. // 4段共阳数码管显示的数值的千位、
  3. // 百位、十位、个位
  4. int k_num=0,h_num=0,d_num=0,g_num=0;
  5.  
  6. // 全局变量SEG4_X用来存放seg4_led_init()函数初始化的
  7. // 4段共阳数码管使用的I/O引脚号。
  8. int SEG4_con1,SEG4_con2,SEG4_con3,SEG4_con4,
  9.      SEG4_a,SEG4_b,SEG4_c,SEG4_d,SEG4_e,SEG4_f,SEG4_g,SEG4_dp;
  10.  
  11. // 共阴数码管显示码表,使用时需要转换为共阳码表
  12. unsigned char table[10][8]=
  13.             {
  14.                  {0,0,1,1,1,1,1,1},//0
  15.                  {0,0,0,0,0,1,1,0},// 1
  16.                  {0,1,0,1,1,0,1,1},// 2
  17.                  {0,1,0,0,1,1,1,1},// 3
  18.                  {0,1,1,0,0,1,1,0},// 4
  19.                  {0,1,1,0,1,1,0,1},// 5
  20.                  {0,1,1,1,1,1,0,1},// 6
  21.                  {0,0,0,0,0,1,1,1},// 7
  22.                  {0,1,1,1,1,1,1,1},// 8
  23.                  {0,1,1,0,1,1,1,1},// 9
  24.             };

然后在seg4_led.h中使用extern声明这些全局变量,别的cpp文件/c文件如果要使用这些全局变量,直接包含seg4_led.h文件即可。

 
  1. // 声明使用的全局变量和数码管显示码表
  2. extern int k_num,h_num,d_num,g_num;
  3. extern int SEG4_con1,SEG4_con2,SEG4_con3,SEG4_con4,
  4.      SEG4_a,SEG4_b,SEG4_c,SEG4_d,SEG4_e,SEG4_f,SEG4_g,SEG4_dp;
  5. extern unsigned char t_table[10][8];


如果把这些全局变量直接定义在seg4_led.h头文件中,则链接时容易造成“全局变量重复定义”错误。
使用全局变量的一个原则:全局变量最好在.cpp/.C文件中定义,在.h文件中加上extern申明,因为在.h文件中定义,容易在链接时造成变量重定义。具体请参考:https://blog.csdn.net/xxxxxx91116/article/details/7446455










 

你可能感兴趣的:(mblock控制SG90舵机模块)