zoukankan      html  css  js  c++  java
  • 【树莓派+.NET MF打造视频监控智能车】控制篇(.NET MF)

    在上一篇《遥控篇》文章中,我们介绍了Sony PS2手柄信号的采集和编程,通过简单的封装,以事件的方式向我们提供按键信息。本篇文章主要介绍.NET Micro Framework系统接受到按键信息后,如何驱动小车马达和控制机械手的。

    无论是驱动小车马达还是控制机械手,都是通过输出PWM来控制的,只是控制PWM输出的方式有些不同而已,我们先介绍一下小车马达的控制。

    由于驱动马达需要相对比较大的电流,所以主芯片的IO是无法直接驱动的,中间需要连接一个驱动器。也就是说主芯片输出PWM控制驱动器,由驱动器输出大电流来驱动马达。

    一般情况下一个驱动器可以驱动两路马达,而驱动一个马达一般需要两路信号,通过控制两路PWM的输出,来控制马达的转速和方向。我们这款小车选用的是一个带光电隔离,高功率的一个驱动器,一路马达,需要三路IO控制,其中2路是控制方向,一路输出PWM控制小车的转速。

     

    一个驱动器模块,需要4个GPIO(控制方向)2路PWM,加上一路3V3和GND,共8路,我们采用标准.NET Gadgeteer接口进行连接(10个pin:1个3V3,1个5V,1个GND,7个GPIO通道),可以直接插入凌霄开发板上的两个.NET Gadgeteer接口上,接线显的简单直接(上图所示的两个扁平电缆就是)。

    机械手控制就更为容易了,一个舵机三根线,电源(5V),地和信号线(PWM),三个舵机,一共需要3路PWM输出控制。注意电源也需要特别提供。PWM由凌霄开发板IO直接输出。

    下面介绍一下.NET Micro Framework的PWM接口函数类。

    public class PWM : IDisposable
    
        {
    
            public PWM(Cpu.PWMChannel channel, double frequency_Hz, double dutyCycle, bool invert);
    
            public PWM(Cpu.PWMChannel channel, uint period, uint duration, PWM.ScaleFactor scale, bool invert);
    
     
    
            public uint Duration { get; set; }
    
            public double DutyCycle { get; set; }
    
            public double Frequency { get; set; }
    
            public uint Period { get; set; }
    
         
    
            public void Start();
    
           public void Stop();
    
          
    
          //… 省略一些非主要函数
    
       }

    两个构造函数,分别介绍一下。

    PWM(Cpu.PWMChannel channel, double frequency_Hz, double dutyCycle, bool invert);

    channel – 通道,不同的系统,支持的通道个数不同,比如凌霄系统支持16路,应该算比较多的。

    frequency_Hz – 频率,单位是Hz,发出脉冲的频率值。

    dutyCycle – 占空比, 一个0~1之间的数,表示一个周期中,高电平持续时间和整个周期的比值。

    Invert – 信号翻转,高低电平翻转切换,一般底层都没有处理该参数,所以一般设置为false。

     

    public PWM(Cpu.PWMChannel channel, uint period, uint duration, PWM.ScaleFactor scale, bool invert);

    channel – 通道。

    period – 周期。单位和scale的选项一致。

    duration – 高电平持续时间,单位和周期一致。

    scale – 周期的时间单位,可以是毫秒、微秒、纳秒,建议选择微秒。

    Invert – 信号翻转。

     

    第一个构造函数,一般控制马达用,参数设置显的比较直观。频率可以是1K~250KHz(建议10K左右),通过设置占空比的大小(0就是停止,1就是全速),来进行调速。

    第二个构造函数,适合控制舵机用,舵机典型的控制曲线如下:

     

    F就是所谓的周期了,如果我们设置scale为微秒,则可以直接设置为20000,所谓的脉宽就是duration的值,你可以设置为1000~2000之间(不同舵机,这个区域的值会有不同,请根据实际进行调整)。

    有了以上的介绍,我们就可以很容易地完成马达驱动和舵机控制了。

    A.驱动马达

    马达驱动控制参数定义:   

     static PWM[] motor_pwm = new PWM[4];
    
        static double[] frequency = new double[] { 10000, 10000, 10000, 10000 };        
    
        static double[] dutyCycle = new double[] { 0, 0, 0, 0};                         
    
        static bool[] states1 = new bool[] { true, false, true, false, true, false, true, false };
    
        static bool[] states2 = new bool[] { false, true, false, true, false, true, false, true };
    
        static OutputPort[] In = new OutputPort[8];

    马达驱动初始化:

      

      //初始化马达控制
    
        //方向IO
    
        Cpu.Pin[] pins = new Cpu.Pin[] { Mainboard.Gadgeteer.Socket2.Pin4, Mainboard.Gadgeteer.Socket2.Pin5, Mainboard.Gadgeteer.Socket2.Pin6, Mainboard.Gadgeteer.Socket2.Pin7,
    
                                            Mainboard.Gadgeteer.Socket1.Pin4, Mainboard.Gadgeteer.Socket1.Pin5, Mainboard.Gadgeteer.Socket1.Pin6, Mainboard.Gadgeteer.Socket1.Pin7};           
    
        for (int i = 0; i < In.Length; i++)
    
        {
    
            In[i] = new OutputPort(pins[i], false);
    
        }
    
        //马达速度PWM输出
    
        Cpu.PWMChannel[] motor_chanels = new Cpu.PWMChannel[] { Mainboard.PWM.Channel13, Mainboard.PWM.Channel14, Mainboard.PWM.Channel2, Mainboard.PWM.Channel3 };
    
        for (int i = 0; i < motor_pwm.Length; i++)
    
        {
    
            motor_pwm[i] = new PWM(motor_chanels[i], frequency[i], dutyCycle[i], false);
    
            motor_pwm[i].Start();
    
        }
    
     

    马达控制:

    在Sony PS2的事件代码中,我们填写如下代码:

    static void ps2_Click(object sender, PS2.ButtonArgs e)
    
        {
    
    if(e.key == PS2.Key.RRocker)
    
            {
    
                PS2 ps2 = (PS2)sender;
    
                PS2.ButtonArgs button = ps2.GetButton(PS2.Key.L2);
    
                if (button.state == 1) //L2按下
    
                {
    
                    byte[] buffer = new byte[] { 0xAA, (byte)e.x, (byte)e.y, 0x55 };
    
                    piPort.Write(buffer, 0, 4);
    
                    piPort.Flush();
    
     
    
                    //左右旋转
    
                    steering_pwm[3].Duration = (UInt32)(durations[3] + (128 - e.x) * 5);
    
                    //上下旋转
    
                    steering_pwm[4].Duration = (UInt32)(durations[4] + (128 - e.y) * 5);
    
     
    
                }
    
                Else  //L2抬起
    
                {
    
                    //小车运动
    
                    UInt32[] values = new UInt32[4];
    
                    UInt32 x = (UInt32)(System.Math.Abs(e.x - 128));
    
                    UInt32 y = (UInt32)(System.Math.Abs(e.y - 128));
    
                    for (int i = 0; i < values.Length; i++) values[i] = y;
    
     
    
                    if (e.y < 128)
    
                    {
    
                        //前进
    
                        for (int i = 0; i < In.Length; i++) In[i].Write(states2[i]);
    
                        //拐弯
    
                        if (x > 30)
    
                        {
    
                            if (e.x < 128)
    
                            {
    
                                values[2] = x;
    
                                values[3] = x;
    
                            }
    
                            else
    
                            {
    
                                values[0] = x;
    
                                values[1] = x;
    
                            }
    
                        }
    
                    }
    
                    else
    
                    {
    
                        //后退
    
                        for (int i = 0; i < In.Length; i++) In[i].Write(states1[i]);
    
                        //拐弯
    
                        if (x > 30)
    
                        {
    
                            if (e.x < 128)
    
                            {
    
                                values[0] = x;
    
                                values[1] = x;
    
                            }
    
                            else
    
                            {
    
                                values[2] = x;
    
                                values[3] = x;
    
                            }
    
                        }
    
                    }
    
                    //设置占空比
    
                    for (int i = 0; i < motor_pwm.Length; i++) motor_pwm[i].DutyCycle = (values[i] / 128.0);
    
                }
    
            }
    
        }      

    B、驱动舵机

    舵机参数定义:

    static PWM[] steering_pwm = new PWM[5];
    
        static UInt32[] periods = new UInt32[] { 20000, 20000, 20000, 20000, 20000 };//周期        static UInt32[] durations = new UInt32[] { 1390, 1500, 1390, 1550, 1420 };   //脉宽

    舵机初始化:

    Cpu.PWMChannel[] steering_chanels = new Cpu.PWMChannel[] { Mainboard.PWM.Channel8, Mainboard.PWM.Channel9, Mainboard.PWM.Channel6, Mainboard.PWM.Channel0, Mainboard.PWM.Channel4 };
    
        for (int i = 0; i < steering_pwm.Length; i++)
    
        {
    
            steering_pwm[i] = new PWM(steering_chanels[i], periods[i], durations[i], PWM.ScaleFactor.Microseconds, false);
    
            steering_pwm[i].Start();
    
        }

    舵机控制:

    static void ps2_Click(object sender, PS2.ButtonArgs e)
    
        {
    
           if (e.key == PS2.Key.LRocker) //左摇杆事件
    
            {
    
                //控制机械臂左右旋转
    
                steering_pwm[0].Duration = (UInt32)(durations[0] + (128 - e.x) * 5);
    
                //控制机械臂上下旋转
    
                steering_pwm[1].Duration = (UInt32)(durations[1] + (128 - e.y) * 5);
    
            }
    
            else if (e.key == PS2.Key.R2)  //按下右R2键
    
            {
    
                //打开钳子
    
                value += 10; if (value > 255) value = 255;
    
                steering_pwm[2].Duration = (UInt32)(durations[2] + (value - 128) * 5);
    
            }
    
            else if (e.key == PS2.Key.R1)  //按下右R1键
    
            {  
    
                //闭合钳子
    
                value -= 10;if (value < 0) value = 0;
    
                steering_pwm[2].Duration = (UInt32)(durations[2] + (value - 128) * 5);
    
            }
    
         }

    C、视频演示

     

    视频链接:http://v.youku.com/v_show/id_XNjY2MTE1NjQ0.html

    文章导航:

    1、【树莓派+.NET MF打造视频监控智能车】遥控篇

    2、【树莓派+.NET MF打造视频监控智能车】控制篇(.NET MF)

    3、【树莓派+.NET MF打造视频监控智能车】控制篇(树莓派)

    4、【树莓派+.NET MF打造视频监控智能车】视频篇

     小结:

    1、 .NET Micro Framework PWM类的设计,非常符合用户的认知和使用习惯,可以非常方便地实现相应功能。

    2、 通过VS2010/VS2012在线调试,可以快速地测试出合适的控制值。

    3、 以上代码大概十几分钟就可以完成,充分体现了.NET Micro Framework快速开发的特性。

  • 相关阅读:
    SQL学习
    FOR XML PATH
    IOS学习网址
    weak nonatomic strong等介绍(ios)
    UVALive3045 POJ2000 ZOJ2345 Gold Coins
    UVA713 UVALive5539 POJ1504 ZOJ2001 Adding Reversed Numbers
    UVA713 UVALive5539 POJ1504 ZOJ2001 Adding Reversed Numbers
    UVA439 POJ2243 HDU1372 ZOJ1091 Knight Moves【BFS】
    UVA439 POJ2243 HDU1372 ZOJ1091 Knight Moves【BFS】
    UVA10905 Children's Game
  • 原文地址:https://www.cnblogs.com/yefanqiu/p/3534345.html
Copyright © 2011-2022 走看看