• 伺服电机(servo motor ) ... 伺服电机转子转速受输入信号控制,并能快速反应,在自动控制系统中,用作执行元件,且具有机电时间常数小、线性度高、始动电压等特性,可把所收到的电信号转换成电动机轴...

    常规舵机
    某型号舵机参数简介


    伺服电机(servo motor )

    伺服电机是指在伺服系统中控制机械元件运转的发动机,是一种补助马达间接变速装置。
    伺服电机可以控制速度,位置精度非常准确,可以将电压信号转化为转矩和转速以驱动控制对象。
    伺服电机转子转速受输入信号控制,并能快速反应,在自动控制系统中,用作执行元件,且具有机电时间常数小、线性度高、始动电压等特性,可把所收到的电信号转换成电动机轴上的角位移或角速度输出。分为直流和交流伺服电动机两大类,其主要特点是,当信号电压为零时无自转现象,转速随着转矩的增加而匀速下降。


    舵机

    舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前,在高档遥控玩具,如飞机、潜艇模型,遥控机器人中已经得到了普遍应用。
    舵机主要是由外壳、电路板、驱动马达、减速器与位置检测元件所构成。其工作原理是由接收机发出讯号给舵机,经由电路板上的 IC驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回讯号,判断是否已经到达定位。
    位置检测器其实就是可变电阻,当舵机转动时电阻值也会随之改变,藉由检测电阻值便可知转动的角度。
    一般的伺服马达是将细铜线缠绕在三极转子上,当电流流经线圈时便会产生磁场,与转子外围的磁铁产生排斥作用,进而产生转动的作用力。依据物理学原理,物体的转动惯量与质量成正比,因此要转动质量愈大的物体,所需的作用力也愈大。舵机为求转速快、耗电小,于是将细铜线缠绕成极薄的中空圆柱体,形成一个重量极轻的无极中空转子,并将磁铁置於圆柱体内,这就是空心杯马达。
    为了适合不同的工作环境,有防水及防尘设计的舵机;并且因应不同的负载需求,舵机的齿轮有塑胶及金属之区分,金属齿轮的舵机一般皆为大扭力及高速型,具有齿轮不会因负载过大而崩牙的优点。较高级的舵机会装置滚珠轴承,使得转动时能更轻快精准。


    伺服电机与步进电机的性能比较

    步进电机作为一种开环控制的系统,和现代数字控制技术有着本质的联系。在目前国内的数字控制系统中,步进电机的应用十分广泛。随着全数字式交流伺服系统的出现,交流伺服电机也越来越多地应用于数字控制系统中。为了适应数字控制的发展趋势,运动控制系统中大多采用步进电机或全数字式交流伺服电机作为执行电动机。虽然两者在控制方式上相似(脉冲串和方向信号),但在使用性能和应用场合上存在着较大的差异。

    现就二者的使用性能进行如下比较:
    • 控制精度不同
      两相混合式步进电机步距角一般为 1.8°、0.9°,五相混合式步进电机步距角一般为0.72 °、0.36°。也有一些高性能的步进电机通过细分后步距角更小。如三洋公司(SANYO DENKI)生产的二相混合式步进电机其步距角可通过拨码开关设置为1.8°、0.9°、0.72°、0.36°、0.18°、0.09°、0.072°、0.036°,兼容了两相和五相混合式步进电机的步距角。
      交流伺服电机的控制精度由电机轴后端的旋转编码器保证。以三洋全数字式交流伺服电机为例,对于带标准2000线编码器的电机而言,由于驱动器内部采用了四倍频技术,其脉冲当量为360°/8000=0.045°。对于带17位编码器的电机而言,驱动器每接收131072个脉冲电机转一圈,即其脉冲当量为360°/131072=0.0027466°,是步距角为1.8°的步进电机的脉冲当量的1/655。
    • 低频特性不同
      步进电机在低速时易出现低频振动现象。振动频率与负载情况和驱动器性能有关,一般认为振动频率为电机空载起跳频率的一半。这种由步进电机的工作原理所决定的低频振动现象对于机器的正常运转非常不利。当步进电机工作在低速时,一般应采用阻尼技术来克服低频振动现象,比如在电机上加阻尼器,或驱动器上采用细分技术等。
      交流伺服电机运转非常平稳,即使在低速时也不会出现振动现象。交流伺服系统具有共振抑制功能,可涵盖机械的刚性不足,并且系统内部具有频率解析机能(FFT),可检测出机械的共振点,便于系统调整。
    • 矩频特性不同
      步进电机的输出力矩随转速升高而下降,且在较高转速时会急剧下降,所以其最高工作转速一般在300~600RPM。交流伺服电机为恒力矩输出,即在其额定转速(一般为2000RPM或3000RPM)以内,都能输出额定转矩,在额定转速以上为恒功率输出。
    • 过载能力不同
      步进电机一般不具有过载能力。交流伺服电机具有较强的过载能力。以三洋交流伺服系统为例,它具有速度过载和转矩过载能力。其最大转矩为额定转矩的二到三倍,可用于克服惯性负载在启动瞬间的惯性力矩。步进电机因为没有这种过载能力,在选型时为了克服这种惯性力矩,往往需要选取较大转矩的电机,而机器在正常工作期间又不需要那么大的转矩,便出现了力矩浪费的现象。
    • 运行性能不同
      步进电机的控制为开环控制,启动频率过高或负载过大易出现丢步或堵转的现象,停止时转速过高易出现过冲的现象,所以为保证其控制精度,应处理好升、降速问题。交流伺服驱动系统为闭环控制,驱动器可直接对电机编码器反馈信号进行采样,内部构成位置环和速度环,一般不会出现步进电机的丢步或过冲的现象,控制性能更为可靠。
    • 速度响应性能不同
      步进电机从静止加速到工作转速(一般为每分钟几百转)需要200~400毫秒。交流伺服系统的加速性能较好,以山洋400W交流伺服电机为例,从静止加速到其额定转速3000RPM仅需几毫秒,可用于要求快速启停的控制场合。
      综上所述,交流伺服系统在许多性能方面都优于步进电机。但在一些要求不高的场合也经常用步进电机来做执行电动机。所以,在控制系统的设计过程中要综合考虑控制要求、成本等多方面的因素,选用适当的控制电机。

    伺服电机优点【其他电机(如步进电机)相比】:


    1、精度:实现了位置,速度和力矩的闭环控制;克服了步进电机失步的问题;


    2、转速:高速性能好,一般额定转速能达到2000~3000转;


    3、适应性:抗过载能力强,能承受三倍于额定转矩的负载,对有瞬间负载波动和要求快速起动的场合特别适用;


    4、稳定:低速运行平稳,低速运行时不会产生类似于步进电机的步进运行现象。适用于有高速响应要求的场合;


    5、及时性:电机加减速的动态相应时间短,一般在几十毫秒之内;


    6、舒适性:发热和噪音明显降低。


    简单点说就是:平常看到的那种普通的电机,断电后它还会因为自身的惯性再转一会儿,然后停下。而伺服电机和步进电机是说停就停,说走就走,反应极快。但步进电机存在失步现象。


    舵机控制

    舵机有很多规格,但所有的舵机都有外接三根线,分别用棕、红、橙三种颜色进行区分:棕色为接地线,红色为电源正极线,橙色为信号线。由于舵机品牌不同,颜色也会有所差异


    • 舵机工作原理:

    由接收机或者单片机发出信号给舵机,其内部有一个基准电路,产生周期为20ms,宽度为1.5ms 的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。经由电路板上的IC 判断转动方向,再驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回信号,判断是否已经到达定位。
    适用于那些需要角度不断变化并可以保持的控制系统。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。一般舵机旋转的角度范围是0 度到180 度。
    舵机的转动的角度是通过调节PWM(脉冲宽度调制)信号的占空比来实现的,标准PWM(脉冲宽度调制)信号的周期固定为20ms(50Hz)。
    理论上脉宽分布应在1ms到2ms 之间,但是,事实上脉宽可由0.5ms 到2.5ms 之间,脉宽和舵机的转角0°~180°相对应。
    由于舵机品牌不同,对于同一信号,不同舵机旋转的角度也会有所不同。
    PWM角度调节


    实例演示

        了解了上面这些烦人的基础知识,下面我们进行一个通过Arduino控制舵机的实例。
    

    本实验所需要的元器件很少:Arduino Pro MINI*1、舵机*1、跳线若干。

    用Arduino 控制舵机的方法有两种:
    • 第一种是通过Arduino具备PWM的数字I/O接口产生占空比不同的方波,模拟产生PWM 信号进行舵机定位.

    • 第二种是直接利用Arduino 自带的Servo 函数进行舵机控制,这种控制方法的优点在于程序编写简便,缺点是只能控制2 路舵机。因为Arduino 自带函数只能利用D9、D10 接口。
      Arduino 的驱动能力有限,所以当需要控制1 个以上的舵机时需要外接电源。

    实物连接


    方法1代码示例:

    
        /**
         通过串口,让舵机转动到用户输入数字所对应的角度数的位置。
         将角度打印显示到屏幕上。
         将舵机信号线接在D3接口
         */
        int servoPin = 3;    //定义D3连接伺服舵机信号线3,5,6,9,10,11均可
        int myAngle;      //定义角度变量
        int val;
        void setup(){
            pinMode(servoPin,OUTPUT);//设定舵机接口为输出接口
            Serial.begin(9600);//连接到串行端口,波特率为9600
            Serial.println("Please input Angle." );
        }
        void loop(){
            val=Serial.read();    //读取串行端口的值
            if(val>='0' && val<='9'){
            val = val - '0';    //将特征量转化为数值变量,
            myAngle = val*(180/9);//将数字转化为角度
            Serial.print("moving servo to ");
            Serial.print(val,DEC);
            Serial.println();
            analogWrite(servoPin,myAngle);
            }
        }

    方法1实物连接示意


    方法2代码示例:
    Arduino
    #include <Servo.h>
    /**
    attach()
    设定舵机的接口,只有9或10接口可利用。
    write()
    用于设定舵机旋转角度的语句,可设定的角度范围是0°到180°。
    writeMicroseconds() 
    用于设定舵机旋转角度的语句,直接用微秒作为参数。
    read()
    用于读取舵机角度的语句,可理解为读取最后一条write()命令中的值。
    attached()
    判断舵机参数是否已发送到舵机所在接口。
    detach()
    使舵机与其接口分离,该接口(9或10)可继续被用作PWM接口。
    */
    Servo myservo; // create servo object to control a servo
    // a maximum of eight servo objects can be created
    int pos = 0; // variable to store the servo position
    void setup(){
    myservo.attach(9); // attaches the servo on pin 9 to the servo object
    }
    void loop(){
    pos = 90;
    myservo.write(pos); // 设定舵机转动的初始角度
    delay(100);
    for(pos; pos < 135; pos++){ // 设置转动角 1-180向右转,每一步转动1度
    myservo.write(pos); //设定舵机转动的角度
    delay(100);
    }
    delay(1000);
    pos = 90;
    myservo.write(pos);
    delay(1000);
    for(pos; pos>=45; pos--){
    myservo.write(pos);
    delay(100);
    }
    }

    方法2实物连接示意

    以上就是控制舵机的两种方法,各有优缺点大家根据自己的喜好和需要进行选择。不足之处还请大家批评指正。


        感谢一直关注着禾灮成长进步的朋友们。你们的信任、支持和鼓励,鞭策着我们一路走到了今天。
    
        感谢所有的合作伙伴,我们相互促进,共同见证了彼此的成长。
    
        感谢所有曾经在禾灮彼此倚靠、相互鼓励、携手同心、砥砺同行的兄弟姐妹。这里承载了我们的青春与热血。
    
                    禾灮,感谢有你。
    
        未来,我们将一如既往,砥砺前行。
    
                                            禾灮·小楊
                                           2018.07.04
    

    展开全文
  • 在自动控制系统中, 交流伺服电机的作用是把控制电压信号或相位信号变换成机械位移, 也就是把接收到的电信号变为电机的一定转速或角位移,因此可以用单片机实现对电机的数字控制
  • STM32伺服电机控制

    2020-07-11 23:31:41
    STM32伺服电机控制,串口,支持G代码解析,移植方便,
  • 仿pioneer3at的机器人,缺点当负载过大时,会产生跳齿等问题,效果一般电机使用的是富兴公司的伺服电机 控制参考:步进电机与ros通信,做的can与stm32通信,进行轮速的设定和位置的反馈,对反馈的编码值进行处理...

    仿pioneer3at的机器人,缺点当负载过大时,会产生跳齿等问题,效果一般电机使用的是富兴公司的伺服电机

      控制参考:步进电机与ros通信,做的can与stm32通信,进行轮速的设定和位置的反馈,对反馈的编码值进行处理,得到移动平台的位置姿态,通过STM32的串口反馈给ros.加了遥控器遥控

    程序可参考https://www.ncnynl.com/archives/201703/1416.html

    将STM32程序下载到STM32上,ROS程序写好。

    将STM32线连接到笔记本

    roscore

    sudo chmod a+rw /dev/ttyUSB0

    rosrun base_controller base_controller

    rosrun teleop_twist_keyboard teleop_twist_keyboard.py
    就可以控制下位机小车移动了

    #include "stm32f10x.h"
    #include "stm32f10x_it.h"
    #include "rcc_conf.h"
    #include "led.h"
    #include "delay.h"
    #include "key.h"
    #include "sys.h"
    #include "lcd.h"
    #include "usart.h"     
    #include "can.h" 
    #include "CONTACT.h"
    #include "nvic_conf.h"
    #include "odometry.h"
    #include "tim2_5_6.h"
    #include "stdbool.h"
    #include <stdio.h>
    #include "string.h"
    #include "math.h"
    char odometry_data[21]={0};   //发送给串口的里程计数据数组
    
    float odometry_right=0,odometry_left=0;//串口得到的左右轮速度
    int i,j,m,t;
    
    /***********************************************  输入  *****************************************************************/
    
    extern float position_x,position_y,oriention,velocity_linear,velocity_angular;         //计算得到的里程计数值
    extern u8 USART_RX_BUF[USART_REC_LEN];     //串口接收缓冲,最大USART_REC_LEN个字节.
    extern u16 USART_RX_STA;                   //串口接收状态标记    
    
    extern float Milemeter_L_Motor,Milemeter_R_Motor;     //dt时间内的左右轮速度,用于里程计计算
    
    u8 main_sta=0; //用作处理主函数各种if,去掉多余的flag(1打印里程计)(2调用计算里程计数据函数)(3串口接收成功)(4串口接收失败)
    
    union recieveData  //接收到的数据
    {
        float d;    //左右轮速度
        unsigned char data[4];
    }leftdata,rightdata;       //接收的左右轮数据
    
    union odometry  //里程计数据共用体
    {
        float odoemtry_float;
        unsigned char odometry_char[4];
    }x_data,y_data,theta_data,vel_linear,vel_angular;     //要发布的里程计数据,分别为:X,Y方向移动的距离,当前角度,线速度,角速度
    
    int main(void)
    {     
        unsigned char key_485;
        u8 i=0,t=0;
        delay_init();             //延时函数初始化      
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
        uart_init(115200);         //串口初始化为115200
        LED_Init();                  //初始化与LED连接的硬件接口
        LCD_Init();                   //初始化LCD    
        KEY_Init();                //按键初始化             
      CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps 
         
        RCC_Configuration();      //系统时钟配置        
        TIM2_PWM_Init();          //PWM输出初始化
        TIM5_Configuration();     //速度计算定时器初始化
        TIM1_Configuration();     //里程计发布定时器初始化
        NVIC_Configuration();     //中断优先级配置
        MOTOR_init();//电机初始化
      while(1)
         {
                key_485=KEY_Scan(0);
                if (key_485==1)
                    {
                    MOTOR_stop();
                    }
                if (key_485==2)
                    {
                    MOTOR_speed(300,300);
                    } 
                if(main_sta&0x01)//执行发送里程计数据步骤
              {
          //里程计数据获取
                x_data.odoemtry_float=position_x;//单位mm
                y_data.odoemtry_float=position_y;//单位mm
                theta_data.odoemtry_float=oriention;//单位rad
                vel_linear.odoemtry_float=velocity_linear;//单位mm/s
                vel_angular.odoemtry_float=velocity_angular;//单位rad/s
                
          LCD_ShowxNum(60,80,210,24,24,position_x);  
          LCD_ShowxNum(90,80,210,24,24,position_y);             
                //将所有里程计数据存到要发送的数组
                    for(j=0;j<4;j++)
                    {
                        odometry_data[j]=x_data.odometry_char[j];
                        odometry_data[j+4]=y_data.odometry_char[j];
                        odometry_data[j+8]=theta_data.odometry_char[j];
                        odometry_data[j+12]=vel_linear.odometry_char[j];
                        odometry_data[j+16]=vel_angular.odometry_char[j];
                    }
                
                  odometry_data[20]='\n';//添加结束符
                
                    //发送数据要串口
                    for(i=0;i<21;i++)
                    {
                        USART_ClearFlag(USART1,USART_FLAG_TC);  //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题                
                        USART_SendData(USART1,odometry_data[i]);//发送一个字节到串口    
                        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);    //等待发送结束        
                        LCD_ShowString(30,80,210,24,24,"Send");                
                    }
                
                  main_sta&=0xFE;//执行计算里程计数据步骤
              }
            if(main_sta&0x02)//执行计算里程计数据步骤
            {
                odometry(Milemeter_R_Motor,Milemeter_L_Motor);//计算里程计
            
                main_sta&=0xFD;//执行发送里程计数据步骤
            }
                if(main_sta&0x08)        //当发送指令没有正确接收时
                    {
                     USART_ClearFlag(USART1,USART_FLAG_TC);  //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题
                        for(m=0;m<3;m++)
                        {
                                USART_SendData(USART1,0x00);    
                                while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
                        }        
                        USART_SendData(USART1,'\n');    
                        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);    
                        main_sta&=0xF7;
                    }
          if(USART_RX_STA&0x8000)  // 串口1接收函数
                    {            
                        LCD_ShowString(30,100,210,24,24,"Rec");
                        //接收左右轮速度
                        for(t=0;t<4;t++)
                        {
                            rightdata.data[t]=USART_RX_BUF[t];
                            leftdata.data[t]=USART_RX_BUF[t+4];
                        }
                        
                        //储存左右轮速度
                        odometry_right=rightdata.d;//单位mm/s
                        odometry_left=leftdata.d;//单位mm/s
                        LCD_ShowxNum(60,120,210,24,24,odometry_right);
                        LCD_ShowxNum(60,140,210,24,24,odometry_left);
                        USART_RX_STA=0;//清楚接收标志位
                        MOTOR_speed(rightdata.d,leftdata.d);     //将接收到的左右轮速度赋给小车    
                    }
       }
    
    }


     

    /******************************************************************
    基于串口通信的ROS小车基础控制器,功能如下:
    1.实现ros控制数据通过固定的格式和串口通信,从而达到控制小车的移动
    2.订阅了/cmd_vel主题,只要向该主题发布消息,就能实现对控制小车的移动
    3.发布里程计主题/odm
    
    串口通信说明:
    1.写入串口
    (1)内容:左右轮速度,单位为mm/s
    (2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节]
    2.读取串口
    (1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s
    (2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
    *******************************************************************/
    #include "ros/ros.h"  //ros需要的头文件
    #include <geometry_msgs/Twist.h>
    #include <tf/transform_broadcaster.h>
    #include <nav_msgs/Odometry.h>
    //以下为串口通讯需要的头文件
    #include <string>        
    #include <iostream>
    #include <cstdio>
    #include <unistd.h>
    #include <math.h>
    #include "serial/serial.h"
    /****************************************************************************/
    using std::string;
    using std::exception;
    using std::cout;
    using std::cerr;
    using std::endl;
    using std::vector;
    /*****************************************************************************/
    float ratio = 1000.0f ;   //转速转换比例,执行速度调整比例
    float D = 0.412f ;    //两轮间距,单位是m
    float linear_temp=0,angular_temp=0;//暂存的线速度和角速度
    /****************************************************/
    unsigned char data_terminal0=0x0d;  //“/r"字符
    unsigned char data_terminal1=0x0a;  //“/n"字符
    unsigned char speed_data[10]={0};   //要发给串口的数据
    string rec_buffer;  //串口数据接收变量
    
    //发送给下位机的左右轮速度,里程计的坐标和方向
    union floatData //union的作用为实现char数组和float之间的转换
    {
        float d;
        unsigned char data[4];
    }right_speed_data,left_speed_data,position_x,position_y,oriention,vel_linear,vel_angular;
    /************************************************************/
    void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数
    {
        string port("/dev/ttyUSB0");    //小车串口号
        unsigned long baud = 115200;    //小车串口波特率
        serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口
    
        angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/s
        linear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s
    
        //将转换好的小车速度分量为左右轮速度
        left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;
        right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;
        //left_speed_data.d=angular_temp;
        //right_speed_data.d=linear_temp;
        //存入数据到要发布的左右轮速度消息
        left_speed_data.d*=ratio;   //放大1000倍,mm/s
        right_speed_data.d*=ratio;//放大1000倍,mm/s
    
        for(int i=0;i<4;i++)    //将左右轮速度存入数组中发送给串口
        {
            speed_data[i]=right_speed_data.data[i];
            speed_data[i+4]=left_speed_data.data[i];
        }
    
        //在写入串口的左右轮速度数据后加入”/r/n“
        speed_data[8]=data_terminal0;
        speed_data[9]=data_terminal1;
        //写入数据到串口
        my_serial.write(speed_data,10);
    }
    int main(int argc, char **argv)
    {
        string port("/dev/ttyUSB0");//小车串口号
        unsigned long baud = 115200;//小车串口波特率
        serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000));//配置串口
    
        ros::init(argc, argv, "base_controller");//初始化串口节点
        ros::NodeHandle n;  //定义节点进程句柄
    
        ros::Subscriber sub = n.subscribe("cmd_vel", 20, callback); //订阅/cmd_vel主题
        ros::Publisher odom_pub= n.advertise<nav_msgs::Odometry>("odom", 20); //定义要发布/odom主题
    
        static tf::TransformBroadcaster odom_broadcaster;//定义tf对象
        geometry_msgs::TransformStamped odom_trans;//创建一个tf发布需要使用的TransformStamped类型消息
        nav_msgs::Odometry odom;//定义里程计对象
        geometry_msgs::Quaternion odom_quat; //四元数变量
        //定义covariance矩阵,作用为解决文职和速度的不同测量的不确定性
        float covariance[36] = {0.01,   0,    0,     0,     0,     0,  // covariance on gps_x
                                0,  0.01, 0,     0,     0,     0,  // covariance on gps_y
                                0,  0,    99999, 0,     0,     0,  // covariance on gps_z
                                0,  0,    0,     99999, 0,     0,  // large covariance on rot x
                                0,  0,    0,     0,     99999, 0,  // large covariance on rot y
                                0,  0,    0,     0,     0,     0.01};  // large covariance on rot z 
        //载入covariance矩阵
        for(int i = 0; i < 36; i++)
        {
            odom.pose.covariance[i] = covariance[i];;
        }       
    
        ros::Rate loop_rate(10);//设置周期休眠时间
        while(ros::ok())
        {
            rec_buffer =my_serial.readline(25,"\n");    //获取串口发送来的数据
            const char *receive_data=rec_buffer.data(); //保存串口发送来的数据
            if(rec_buffer.length()==21) //串口接收的数据长度正确就处理并发布里程计数据消息
            {
                for(int i=0;i<4;i++)//提取X,Y坐标,方向,线速度,角速度
                {
                    position_x.data[i]=receive_data[i];
                    position_y.data[i]=receive_data[i+4];
                    oriention.data[i]=receive_data[i+8];
                    vel_linear.data[i]=receive_data[i+12];
                    vel_angular.data[i]=receive_data[i+16];
                }
                //将X,Y坐标,线速度缩小1000倍
                position_x.d/=1000; //m
                position_y.d/=1000; //m
                vel_linear.d/=1000; //m/s
    
                //里程计的偏航角需要转换成四元数才能发布
          odom_quat = tf::createQuaternionMsgFromYaw(oriention.d);//将偏航角转换成四元数
    
                //载入坐标(tf)变换时间戳
                odom_trans.header.stamp = ros::Time::now();
                //发布坐标变换的父子坐标系
                odom_trans.header.frame_id = "odom";     
                odom_trans.child_frame_id = "base_footprint";       
                //tf位置数据:x,y,z,方向
                odom_trans.transform.translation.x = position_x.d;
                odom_trans.transform.translation.y = position_y.d;
                odom_trans.transform.translation.z = 0.0;
                odom_trans.transform.rotation = odom_quat;        
                //发布tf坐标变化
                odom_broadcaster.sendTransform(odom_trans);
    
                //载入里程计时间戳
                odom.header.stamp = ros::Time::now(); 
                //里程计的父子坐标系
                odom.header.frame_id = "odom";
                odom.child_frame_id = "base_footprint";       
                //里程计位置数据:x,y,z,方向
                odom.pose.pose.position.x = position_x.d;     
                odom.pose.pose.position.y = position_y.d;
                odom.pose.pose.position.z = 0.0;
                odom.pose.pose.orientation = odom_quat;       
                //载入线速度和角速度
                odom.twist.twist.linear.x = vel_linear.d;
                //odom.twist.twist.linear.y = odom_vy;
                odom.twist.twist.angular.z = vel_angular.d;    
                //发布里程计
                odom_pub.publish(odom);
    
                ros::spinOnce();//周期执行
          loop_rate.sleep();//周期休眠
            }
            //程序周期性调用
            //ros::spinOnce();  //callback函数必须处理所有问题时,才可以用到
        }
        return 0;
    }


    键盘控制

    #!/usr/bin/env python
    
    from __future__ import print_function
    
    import roslib; roslib.load_manifest('teleop_twist_keyboard')
    import rospy
    
    from geometry_msgs.msg import Twist
    
    import sys, select, termios, tty
    
    msg = """
    Reading from the keyboard  and Publishing to Twist!
    ---------------------------
    Moving around:
       u    i    o
       j    k    l
       m    ,    .
    
    For Holonomic mode (strafing), hold down the shift key:
    ---------------------------
       U    I    O
       J    K    L
       M    <    >
    
    t : up (+z)
    b : down (-z)
    
    anything else : stop
    
    q/z : increase/decrease max speeds by 10%
    w/x : increase/decrease only linear speed by 10%
    e/c : increase/decrease only angular speed by 10%
    
    CTRL-C to quit
    """
    
    moveBindings = {
            'i':(1,0,0,0),
            'o':(1,0,0,-1),
            'j':(1,0,0,1),
            'l':(1,0,0,-1),
            'u':(1,0,0,1),
            ',':(-1,0,0,0),
            '.':(-1,0,0,1),
            'm':(-1,0,0,-1),
            'O':(1,-1,0,0),
            'I':(1,0,0,0),
            'J':(0,1,0,0),
            'L':(0,-1,0,0),
            'U':(1,1,0,0),
            '<':(-1,0,0,0),
            '>':(-1,-1,0,0),
            'M':(-1,1,0,0),
            't':(0,0,1,0),
            'b':(0,0,-1,0),
               }
    
    speedBindings={
            'q':(1.1,1.1),
            'z':(.9,.9),
            'w':(1.1,1),
            'x':(.9,1),
            'e':(1,1.1),
            'c':(1,.9),
              }
    
    def getKey():
        tty.setraw(sys.stdin.fileno())
        select.select([sys.stdin], [], [], 0)
        key = sys.stdin.read(1)
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
        return key
    
    
    def vels(speed,turn):
        return "currently:\tspeed %s\tturn %s " % (speed,turn)
    
    if __name__=="__main__":
            settings = termios.tcgetattr(sys.stdin)
        
        pub = rospy.Publisher('cmd_vel', Twist, queue_size = 1)
        rospy.init_node('teleop_twist_keyboard')
    
        speed = rospy.get_param("~speed", 0.1)
        turn = rospy.get_param("~turn", 0.4)
        x = 0
        y = 0
        z = 0
        th = 0
        status = 0
    
        try:
            print(msg)
            print(vels(speed,turn))
            while(1):
                key = getKey()
                if key in moveBindings.keys():
                    x = moveBindings[key][0]
                    y = moveBindings[key][1]
                    z = moveBindings[key][2]
                    th = moveBindings[key][3]
                elif key in speedBindings.keys():
                    speed = speed * speedBindings[key][0]
                    turn = turn * speedBindings[key][1]
    
                    print(vels(speed,turn))
                    if (status == 14):
                        print(msg)
                    status = (status + 1) % 15
                else:
                    x = 0
                    y = 0
                    z = 0
                    th = 0
                    if (key == '\x03'):
                        break
    
                twist = Twist()
                twist.linear.x = x*speed; twist.linear.y = y*speed; twist.linear.z = z*speed;
                twist.angular.x = 0; twist.angular.y = 0; twist.angular.z = th*turn
                pub.publish(twist)
    
        except Exception as e:
            print(e)
    
        finally:
            twist = Twist()
            twist.linear.x = 0; twist.linear.y = 0; twist.linear.z = 0
            twist.angular.x = 0; twist.angular.y = 0; twist.angular.z = 0
            pub.publish(twist)
    
                termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)
    
    

    其他学习4个can转向电机4个rs485轮毂电机及4个can编码器

    在linux控制电机程序为:https://download.csdn.net/download/jankin_by/10342919

    调试最后总出现编码器CRC校验错误,怀疑为linux下多串口通信的问题

    改为用单片机直接控制

    https://download.csdn.net/download/jankin_by/10342947

    为了调试方便加了遥控

    展开全文
  • 开始浏览正文之前,请大家先花几分钟看完这段...通俗一点讲:当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(即步进角),是现代数字程序控制系统中的主要执行元件,应用极为...

    开始浏览正文之前,请大家先花几分钟看完这段视频:

    步进电机是如何工作的


    步进电机(stepping motor)

    步进电机

    步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件,是一种将电脉冲转化为角位移的执行机构。通俗一点讲:当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(即步进角),是现代数字程序控制系统中的主要执行元件,应用极为广泛。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。

    在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响。

    当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为”步距角”,它的旋转是以固定的角度一步一步运行的。

    可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。

    步进电机是一种感应电机,它的工作原理是利用电子电路,将直流电变成分时供电的多相时序控制电流,用这种电流为步进电机供电,步进电机才能正常工作,驱动器就是为步进电机分时供电的多相时序控制器。

    虽然步进电机已被广泛地应用,但步进电机并不能像普通的直流电机、交流电机在常规下使用。它必须由双环形脉冲信号、功率驱动电路等组成控制系统方可使用。因此用好步进电机却非易事,它涉及到机械、电机、电子及计算机等许多专业知识。

    步进电机作为执行元件,是机电一体化的关键产品之一,广泛应用在各种自动化控制系统中。随着微电子和计算机技术的发展,步进电机的需求量与日俱增,在各个国民经济领域都有应用。

    步进电机又称为脉冲电机,基于最基本的电磁铁原理,它是一种可以自由回转的电磁铁,其动作原理是依靠气隙磁导的变化来产生电磁转矩。

    由于步进电机是一个把电脉冲转换成离散的机械运动的装置,具有很好的数据控制特性,因此,计算机成为步进电机的理想驱动源,随着微电子和计算机技术的发展,软硬件结合的控制方式成为了主流,即通过程序产生控制脉冲,驱动硬件电路。单片机通过软件来控制步进电机,更好地挖掘出了电机的潜力。因此,用单片机控制步进电机已经成为了一种必然的趋势,也符合数字化的时代趋势。


    步进电机和伺服电机、舵机有何区别?

    伺服电机不仅仅只包含一个电机,通常是包含电机、传感器和控制器的电机系统(具体可以参考伺服电机/舵机 控制)。
    舵机是个俗称,适用于航模上,其实是一种低端的但最常见的伺服电机系统,价格低廉但精度较低。


    单片机控制示例

    51单片机按键控制单反转仿真

    相信通过视频及文字内容,大家对步进电机相关原理已经非常熟悉。下面通过Arduino Pro MINI开发板进行一项简易的步进电机控制实验。
    步进电机内部结构
    步进电机(Stepper/Step/Stepping Motor),主要是依靠定子线圈序列通电,顺次在不同的角度形成磁场,推拉定子旋转。接触步进电机时会有很多容易混淆的概念。比如单极性、双极性、两相八线、四相八线等等。主要是由于线圈的接法不同,我们先简单地辩析一下:按照电机驱动架构可分为单极性 (unipolar) 和双极性 (bipolar) 步进电机。所谓的极性,就是电流通过线圈绕组产生磁场的极性,单极性就是只有一个磁极,双极就是有两个磁极。四相,八相是指步进电机的相数,即步进电机内部的线圈组数。电机的相数不同,步进电机接收到每个脉冲信号的角度也不同。通过不同的极性,不同的相数,线圈接法会得到不同的电机性能。


    实验前要准备的元件
    - 28BYJ-48 五线四相步进电机
    - ULN2003驱动芯片
    - Arduino Pro MINI开发板
    - 杜邦线若干
    28BYJ-48,DC5V,五线四相步进电机


    示例代码一:

        可以直接在Arduino IDE的File> Examples> Stepper> MotorKnob里直接导入示例代码。
    

    Stepper.h是Arduino IDE自带的控制步进电机的标准库。

    电路原理图(电位计10K即可)
    实物连接示意图

        /*
         * MotorKnob
         *
         * A stepper motor follows the turns of a potentiometer
         * (or other sensor) on analog input 0.
         *
         * http://www.arduino.cc/en/Reference/Stepper
         * This example code is in the public domain.
         */
        #include <Stepper.h>
        // change this to the number of steps on your motor
        #define STEPS 100
        // create an instance of the stepper class, specifying
        // the number of steps of the motor and the pins it's
        // attached to
        Stepper stepper(STEPS, 8, 9, 10, 11);
        // the previous reading from the analog input
        int previous = 0;
        void setup() {
          // set the speed of the motor to 30 RPMs
          stepper.setSpeed(30);
        }
        void loop() {
          // get the sensor value
          int val = analogRead(0);
    
          // move a number of steps equal to the change in the
          // sensor reading
          stepper.step(val - previous);
    
          // remember the previous value of the sensor
          previous = val;
        }

    Stepper函数是用来创建步进电机实例的,共有如下两种用法:
    steps代表电机转一圈所用的步数。这个一般是步进电机出厂是就固定的。
    - 也可以通过步距角计算得出:
    转一圈的步数 = 360 / 步距角

                Stepper(steps, pin1, pin2)
                Stepper(steps, pin1, pin2, pin3, pin4)

    pin1,pin2,pin3,pin4是连接至步进电机的引脚。
    根据电机的引线数确定。pin3,pin4是可选的。

        setSpeed(rpms)函数是用来设置步进电机的速度,即每分钟该转的步数。
    
    • 根据实例代码,当转动电位器,步进电机也会转动一定角度。

    示例代码二:

    调用大神写好的库当然可以节约大量的开发时间,不过懂得原理也是非常有必要的。下面通过五线四相步进电机来进行简单说明:

    五线四相步进电机的工作方式
    `四相步进电机可以在:`
        - 四相单拍   : 通电顺序为 A-B-C-D
        - 四相双拍1  : 通电顺序为 AB-BC-CD-DA
        - 四相双拍2  : 通电顺序为 AC-BC-BD-DA
        - 四相八拍   : 通电顺序为 A-AB-B-BC-C-CD-D-DA-A
    `四种工作方式下工作。`
    




    下面依照8拍驱动方式编写相关代码:
        /* Main.ino file 
         * by: 禾灮Studios
         * 
         * Created:   周三 6月 13 2018
         * Processor: Arduino Uno
         * Compiler:  Arduino AVR (Proteus)
         */
        #define motor_pin_1 8       //A
        #define motor_pin_2 9       //B
        #define motor_pin_3 10      //C
        #define motor_pin_4 11      //D
        int shiJian =10;        //参数用于电机调速
    
    
        void steps_to_move_N(){     //逆时针旋转 八拍方式驱动,顺序为A AB B BC C CD D DA
            //1000  
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian); 
            //1100  
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            // 0100  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            // 0110  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            //0010  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            //0011  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, HIGH);
            delay(shiJian);
            //0001  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, HIGH);
            delay(shiJian);
            //1001  
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, HIGH);
            delay(shiJian);
        }
        void steps_to_move_Z(){
            //1001  
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, HIGH);
            delay(shiJian);
            //0001  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, HIGH);
            delay(shiJian);
            //0011  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, HIGH);
            delay(shiJian);
            //0010  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            // 0110  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            // 0100  
            digitalWrite(motor_pin_1, LOW);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            //1100  
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian);
            //1000  
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, LOW);
            digitalWrite(motor_pin_3, LOW);
            digitalWrite(motor_pin_4, LOW);
            delay(shiJian); 
        }
    
        void setup(){  //初始化
            // put your setup code here, to run once:
            // setup the pins on the microcontroller:
            pinMode(motor_pin_1, OUTPUT);
            pinMode(motor_pin_2, OUTPUT);
            pinMode(motor_pin_3, OUTPUT);
            pinMode(motor_pin_4, OUTPUT);
    
            digitalWrite(motor_pin_1, HIGH);
            digitalWrite(motor_pin_2, HIGH);
            digitalWrite(motor_pin_3, HIGH);
            digitalWrite(motor_pin_4, HIGH); 
        }
        void loop(){   // put your main code here, to run repeatedly:
            steps_to_move_Z();
            // steps_to_move_N();
        } 

    示例代码三:

    下面的代码适用于Arduino系列,以及AVR单片机编程,修改后可直接用于其他单片机。
    本段代码是对示例代码二中函数的简化表述方式。

        /* Main.ino file 
         * by: 禾灮Studios
         * 
         * Created:   周三 6月 13 2018
         * Processor: Arduino Uno
         * Compiler:  Arduino AVR (Proteus)
         */
        #define motor_pin_1 8       //A
        #define motor_pin_2 9       //B
        #define motor_pin_3 10      //C
        #define motor_pin_4 11      //D
        int shiJian =10;        //参数用于电机调速   
        //定义八拍方式驱动,顺序为A-AB-B-BC-C-CD-D-DA
        unsigned char clockWise[]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x0d}; 
    
            void zzz(){    //顺时针旋转
              for(int i=0;i<8;i++){
                PORTB = clockWise[i];
                delay(shiJian);
              }
            }
            void fff(){     //逆时针旋转
              for(int i=0;i<8;i++){
                PORTB = clockWise[8-i];
                delay(shiJian);
              } 
            }
    
        void setup(){  //初始化
            // put your setup code here, to run once:
            // setup the pins on the microcontroller:
            DDRB=0xFF;    //端口B设置为输出
            PORTB=0xFF;   //端口B初始值设置为1
        }
        void loop(){   // put your main code here, to run repeatedly:
            zzz();       
            fff();
        }

    实物连接


    以上内容就是控制步进电机的几种简易方法,各有优缺点大家根据自己的喜好和需要进行选择。不足之处还请大家批评指正。


        感谢一直关注着禾灮成长进步的朋友们。你们的信任、支持和鼓励,鞭策着我们一路走到了今天。
    
        感谢所有的合作伙伴,我们相互促进,共同见证了彼此的成长。
    
        感谢所有曾经在禾灮彼此倚靠、相互鼓励、携手同心、砥砺同行的兄弟姐妹。这里承载了我们的青春与热血。
    
                    禾灮,感谢有你。
    
        未来,我们将一如既往,砥砺前行。
    
                                            禾灮·小楊
                                           2018.07.05
    

    展开全文
  • 可以作为简易运动控制控制伺服电机 发脉冲两种目的 1)速度控制 2)位置控制 速度控制目的和模拟量一样,没有什么需要关注的地方 发送脉冲方式为PWM,速率稳定而且资源占用少 stm32位置控制需要获得发送的脉冲数...
  • BLDC电机通过PID控制到达目标位置,挂上负载不能锁住,我将三个上桥全部置高电平,三个下桥全部置低电平 到位停止锁住代码如下:
  • 舵机,又称伺服马达,是一种具有闭环控制系统的机电结构。舵机主要是由外 壳、电路板、无核心马达、齿轮与位置检测器所构成。其工作原理是由控制器发出PWM(脉冲宽度调制)信号给舵机,经电路板上的IC处理后计算出...

    舵机,又称伺服马达,是一种具有闭环控制系统的机电结构。舵机主要是由外 壳、电路板、无核心马达、齿轮与位置检测器所构成。其工作原理是由控制器发出PWM(脉冲宽度调制)信号给舵机,经电路板上的IC处理后计算出转动方向, 再驱动无核心马达转动,透过减速齿轮将动力传至摆臂,同时由位置检测器(电位器)返回位置信号,判断是否已经到达设定位置,一般舵机只能旋转180度。舵机有3根线,棕色为地,红色为电源正,橙色为信号线,但不同牌子的舵机,线的颜色可能不同,需要注意。

    舵机的转动位置是靠控制PWM(脉冲宽度调制)信号的占空比来实现的,标准PWM(脉冲宽度调制)信号的周期固定为20ms,占空比0.5~2.5ms 的正脉冲宽度和舵机的转角-90°~90°(即0~180度)相对应。注意,由于舵机牌子不同,其控制器解析出的脉冲宽度也不同,所以对于同一信号,不同牌子的舵机旋转的角度也不同。其原理是:它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号, 控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

       0.5ms------------0度;

       1.0ms------------45度;

       1.5ms------------90度;

       2.0ms-----------135度;

       2.5ms-----------180度;

     

    采用11.0592MHZ51单片机驱动舵机转动程序如下:

    //上电自动转动
    
    #include <reg52.h>
    
    unsigned char count;      //0.5ms次数标识
    
    sbit pwm =P1^0 ;          //PWM信号输出
    
    sbit jia =P2^4;           //角度增加按键检测IO口
    
    sbit jian =P2^5;           //角度减少按键检测IO口
    
    unsigned char jd;         //角度标识
    
     
    
    sbit pwm1 =P0^0 ;          //PWM信号输出给示波器,检测PWM波用
    
    void delay(unsigned char i)//延时
    
    {
    
      unsigned char j,k;
    
      for(j=i;j>0;j--)
    
        for(k=125;k>0;k--);
    
    }
    
    void Time0_Init()          //定时器0初始化
    
    {
    
    //定时器0装初值 用示波器检测后,11.0592MHZ晶振 定时0.5ms进入中断 装初值如下
    
    TH0  = (65536-445)/256;
    
    TL0  = (65536-445)%256;
    
     
    TMOD = 0x01;    //定时器0工作在方式1   
    
    IE = 0x82;	//IE=0x82=1000 0010 等价于 EA=1 开总中断  ET0=1 开定时器0中断
    
      TR0=1;          //开定时器0
    
    }
    
    void Time0_Int() interrupt 1 //中断程序
    
    {
    
    //重装初值
    
    TH0  = (65536-445)/256;
    
    TL0  = (65536-445)%256;
    
     
    
        if(count< jd)
    
    {
    
     pwm=1;                  //确实小于,PWM输出高电平
    
     pwm1=pwm;              //接示波器用的io口,观测PWM波形用	    }	//判断0.5ms次数是否小于角度标识
    
     //pwm=1;                  //确实小于,PWM输出高电平
    
        else
    
    {
    
     pwm=0;                  //确实小于,PWM输出高电平
    
     pwm1=pwm;             //接示波器用的io口,观测PWM波形用	}
    
        //  pwm=0;                  //大于则输出低电平
    
        count=(count+1);          //0.5ms次数加1
    
        count=count%40;     //次数始终保持为40 即保持周期为20ms
    
    }
    
     
    
    //此注销掉部分为通过按键控制舵机转动的程序,功能为通过jia按键控制正转,
    
    //通过jian按键控制反转
    
    /*void keyscan()              //按键扫描
    
    {
    
       if(jia==0)               //角度增加按键是否按下
    
      {
    
        delay(10);              //按下延时,消抖
    
        if(jia==0)              //确实按下
    
         {
    
          jd++;                 //角度标识加1
    
          count=0;              //按键按下 则20ms周期从新开始
    
          if(jd==6)
    
            jd=5;               //已经是180度,则保持
    
          while(jia==0);        //等待按键放开
    
         }
    
      }
    
      if(jian==0)                //角度减小按键是否按下
    
      {
    
        delay(10);
    
        if(jian==0)
    
         {
    
          jd--;                 //角度标识减1
    
          count=0;
    
          if(jd==0)
    
            jd=1;               //已经是0度,则保持
    
          while(jan==0);
    
         }
    
      }
    
    }*/
    
     
    void main()
    
    {
    
    //上电,舵机自动正反转    
    
    //应注意每次步进是延时函数delay参数的设置,此处延时函数参数设置的并不理想    
    
    while(1)
    
    {
    
      for(jd=1;jd<6;jd++)
    
    {
    
    count=0;
    
    Time0_Init();
    
    delay(50000000);
    
    }
    
    delay(50000000);
    
    for(jd=6;jd>0;jd--)
    
    {
    
    count=0;
    
    Time0_Init();
    
    delay(50000000);
    
    }
    
    }
    
    }


     

    展开全文
  • 舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服...

    介绍

    什么是舵机

    舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前在高档遥控玩具,如航模,包括飞机模型,潜艇模型;遥控机器人中已经使用得比较普遍。舵机是一种俗称,其实是一种伺服马达。

    原理

    1. 控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号,将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

    2.连线

    橙色—————————–信号线

    红色—————————–VCC

    棕色—————————–GND
    3. 占空比
    舵机占空比
    占空比 = t / T;
    舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。想要控制舵机,那么我们就需要一个周期T = 20ms。高电平小t等于0.5ms-2.5ms之间的这样一个方波。

    转动方法

    以180度角度伺服为例,那么对应的控制关系是这样的:

    0.5ms--------------0度;
    1.0ms------------45度;
    1.5ms------------90度;
    2.0ms-----------135度;
    2.5ms-----------180度;

    这只是一种参考数值,具体的参数,请参见舵机的技术参数。
    我们在开发过程中,会发现因为舵机的型号不同,舵机的优劣不同,加上你的单片机晶振时钟的缘故,导致相应时间的角度实际情况会有一定的偏差。

    实现方法

    C51单片机PWM来调节控制它,对于T = 20ms 。我们可以使用定时器来计数。每次0.1ms。如果计数达到200则说明一个周期到了。这是我们常用的定时器方法。
    以我们常用的12MHz和11.0592MHz晶振为例:
    (方式1)
    11.0592MHz晶振——0.1ms THx = 0xff,TLx = 0xa3

    12.0000MHz晶振——0.1ms THx = 0xff,TLx = 0x9c

    编程实例

    定义变量类型,管脚

    #include<reg52.h>
    #include<Delay.h>//自己编写的延时函数放在这里,你们只需要自己写个延时函数就行了
    sbit DJ_PWM=P0^0;
    sbit JG=P0^7;//低电平发光
    typedef unsigned char u8;
    typedef unsigned int u16;
    u8 t=0,g=5;

    定时器初始化

    void dingshi_Init()          
     {    
      TMOD &= 0x00;  //置零
      TMOD |= 0x01;  //TMOD=0x01;定时器0方式1  
      TH0 = 0xff;    //赋初值0.1ms
      TL0 = 0x9c;    //晶振12M
      ET0 = 1;       //定时计数器0溢出中断允许控制位置1
      TR0 = 1;       //打开定时计数器0
      EA=1;          //总中断允许
      }

    定时器中断函数

    void Time_Init() interrupt 1
    {
     TR0=0;//关闭定时器中断
     //因为是定时器方式1,所以需要在这里初值重装
     TH0 = 0xff;    //赋初值0.1ms
        TL0 = 0x9c;    //晶振12M
        if(t<=g)
     {
      DJ_PWM=1;
     }
     else
     {
      DJ_PWM=0;
     }
     t++;
     if (t>=200)//T=20MS清零
     {
      t=0;
     }
     TR0=1;//开启定时器中断
    }

    主函数

    void main()
    {
      dingshi_Init();
      while(1)
      {
      JG=0;
       g=3;//因为我的0度大致在这里,你们可以自己测试
       t=0;
       delay(2000);
       g=11;//90度
       t=0;
       delay(2000);
       g=20;//180
       t=0;
       delay(2000);
      }
    }

    结尾

    如果在后续想学习很多项目实例,比如蓝牙控制舵机。遥控激光赛车,都可以关注我的 项目实战 栏目。欢迎大家交流。

    展开全文
  • 书名:《单片机应用技术选编(4)》(北京航空航天大学出版社.何立民) PDF格式扫描版,全书分为10章,共614页。1997年2月出版。 内容简介 《单片机应用技术选编》系列图书是汇集了多年间国内主要期刊杂志中有关单片机...
  • 本书系统阐述微机测控技术,涉及面宽,包括:计算机控制理论,微机测控系统常用元器件(放大器、比较器、多路模拟开关、集成稳压器、光电招合器、新型传感器、存储器、总线、显示器、键盘、A/D、D从、可编程I/O接口...
  • 电子设计.doc

    2020-07-11 23:31:39
    0265、步进电机单片机控制 0266、采用PROG-110制作的打铃器电路 0267、超声波测距 0268、超声波在超声波测距中的应用 0269、程控信号发生器的设计 0270、出租车计价器论文 0271、大功率开关电源中功率MOSFET的驱动...
  • 步进式电动机  一、前言 步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号...
  • 13.1 什么是舵机 舵机是一种位置(角度)伺服的驱动器,...舵机能够在微机电系统和航模中作为基本的输出执行机构,其简单的控制和输出值使得单片机系统很容易与之连接进行控制。 上图中的三根线: 橙色 ----...
  • i.MX RT跨界处理器具有实时操作和应用处理器级的功能,其已经实际应用在智能交互、工厂自动化、智能支付终端、语音处理和语音识别等领域,这些应用场景已经足以证明i.MX ...
  • 功能是作为ROS的move_group客户端接收ROS规划的机械臂路点信息,进行三次样条插补获得各个关节或自由度的运动PVAT数据,然后通过TCP通信将处理好的数据发送给下位的beaglebone轴控制器: /* ROS action server *...
  • https://blog.csdn.net/ZhangRelay/article/details/97485429 不清楚为何这篇博文点击量如此之高,课程全部资料链接如下: ... ROS机器人操作系统在线练习课程正在逐步完善中,目前以ROS官网中文资料制作, ...
  • 一些医疗检测仪器在检测时需要模拟人体温度环境以确保检测的精确性,本文以STM32为主控制器,电机驱动芯片DRV8834 为驱动器,驱动半导体致冷器(帕尔贴)给散热片加热或者制冷。但由于常规的温度控制存在惯性温度误差...
  • 控制<的维度需要匹配等。更多详细内容可以查看: 机器人感知-视觉部分:https://blog.csdn.net/ZhangRelay/article/details/81352622 并思考:二维空间导航与三维空间抓取操作的异同之处? 机器人的空间、...
  • 结合实例介绍DSP芯片的选用考虑因素  前言  DSP芯片也称数字信号处理器,是一种特别适合于进行数字信号处理运算的微处理器具,其主机应用是实时快速地实现各种数字信号处理算法. 在DSP系统硬件设计中只有选定了DSP...
1 2 3 4
收藏数 66
精华内容 26