查看: 6977|回复: 10

[原创] 自平衡小车-3B 四路PWM控制两个轮前后转动 代码

[复制链接]
  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    连续签到: 1 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5618
    最后登录
    2021-12-22
    发表于 2017-10-23 20:55:34 | 显示全部楼层 |阅读模式
    本帖最后由 okwh 于 2017-11-11 23:40 编辑

    自平衡小车-3B 四路PWM控制两个轮前后转动 代码


    代码设计:  目的: 四路PWM控制两个轮前后转动(转速、方向、同步)
      基于例子SDK_2.2.1_LPCXpresso54114\boards\lpcxpresso54114\driver_examples\sctimer\simple_pwm修改。
      配置管脚Port 11/2/3/4对于SCTSCT0_OUT4-PWM4SCT0_OUT5-PWM5SCT0_OUT6-PWM6SCT0_OUT7-PWM7
           Port 025/26, 是LED6/7绿灯,亮用于标记两个轮子转动方向。增加到 pin_mux.c
    1. #define PORT0_IDX                        0u   /*!< Port index */
    2. #define PORT1_IDX                        1u   /*!< Port index */

    3. #define PIN1_IDX                         1u   
    4. #define PIN2_IDX                         2u   
    5. #define PIN3_IDX                         3u   
    6. #define PIN4_IDX                         4u   

    7. const uint32_t port1_pin1_config = (
    8.     IOCON_PIO_FUNC3 |                                        /* Pin is configured as SCT0_OUT2 */
    9.     IOCON_PIO_MODE_INACT |                                   /* No addition pin function */
    10.     IOCON_PIO_INV_DI |                                       /* Input function is not inverted */
    11.     IOCON_PIO_DIGITAL_EN |                                   /* Enables digital function */
    12.     IOCON_PIO_INPFILT_OFF |                                  /* Input filter disabled */
    13.     IOCON_PIO_OPENDRAIN_DI                                   /* Open drain is disabled */
    14.   );
    15.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN1_IDX, port1_pin1_config);
    16.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN2_IDX, port1_pin1_config);
    17.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN3_IDX, port1_pin1_config);
    18.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN4_IDX, port1_pin1_config);

    19.   const uint32_t port0_pin25_config = (
    20.     IOCON_FUNC0 |                                        /*IO   Pin is configured as FC4_CTS_SDA_SSEL0 */
    21.           IOCON_GPIO_MODE |                                  /* I2C mode */
    22.     IOCON_MODE_PULLUP |
    23.    // IOCON_PIO_INV_DI |                                       /* Input function is not inverted */
    24.     IOCON_PIO_DIGITAL_EN |                                   /* Enables digital function */
    25.     IOCON_PIO_INPFILT_OFF                                   /* Input filter disabled */
    26.   //  IOCON_PIO_I2CDRIVE_LOW |                                 /* Low drive: 4 mA */
    27.   //  IOCON_PIO_I2CFILTER_EN                                   /* I2C 50 ns glitch filter enabled */
    28.   );
    29.   IOCON_PinMuxSet(IOCON, PORT0_IDX, 25, port0_pin25_config); /* PORT0 PIN25 */
    30.   IOCON_PinMuxSet(IOCON, PORT0_IDX, 26, port0_pin25_config); /* PORT0 PIN26 */
    复制代码

      主要代码:
      SCT初始化;Port 11/2/3/4SCT0_OUT-PWM4/5/6/7四管脚输出PWM配置:高有效、占空比、基本时钟记数频率、共同循环周期(率48KHz) 以及每个对应的事件(其实就是脉冲发生和周期的记数匹配以产生PWM);最后开始SCT,就有PWM发生了。
    注意一个PWM对应一个event标记,它们在改变占空比是要用
    1. sctimer_config_t sctimerInfo;
    2.     sctimer_pwm_signal_param_t pwmParam;
    3.     uint32_t sctimerClock;
    4. ..........
    5.         GPIO->DIR[0] |=  1U << 25;
    6.         GPIO->DIR[0] |=  1U << 26;

    7. SCTIMER_GetDefaultConfig(&sctimerInfo);

    8.     /* Initialize SCTimer module */
    9.     SCTIMER_Init(SCT0, &sctimerInfo);

    10.     /* Configure first PWM with frequency 24kHZ from output 4 5      kSCTIMER_CenterAlignedPwm  kSCTIMER_EdgeAlignedPwm*/
    11.     pwmParam.output = kSCTIMER_Out_4;
    12.     pwmParam.level = kSCTIMER_HighTrue;
    13.     pwmParam.dutyCyclePercent = 40;
    14.     if (SCTIMER_SetupPwm(SCT0, &pwmParam,kSCTIMER_CenterAlignedPwm , 48000U, sctimerClock, &event4) == kStatus_Fail)
    15.     {
    16.         return -1;
    17.     }
    18.         
    19.     pwmParam.output = kSCTIMER_Out_5;
    20.     pwmParam.level = kSCTIMER_HighTrue;
    21.     pwmParam.dutyCyclePercent = 40;
    22.     if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event5) == kStatus_Fail)
    23.     {
    24.         return -1;
    25.     }

    26.    /*  Configure second PWM with different duty cycle but same frequency as before */
    27.     pwmParam.output = kSCTIMER_Out_6;
    28.     pwmParam.level = kSCTIMER_HighTrue;
    29.     pwmParam.dutyCyclePercent = 45;
    30.     if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event6) == kStatus_Fail)
    31.     {
    32.         return -1;
    33.     }                                                                    
    34.    pwmParam.output = kSCTIMER_Out_7;
    35.     pwmParam.level = kSCTIMER_HighTrue;
    36.     pwmParam.dutyCyclePercent = 45;
    37.     if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event7) == kStatus_Fail)
    38.     {
    39.         return -1;
    40.     }
    41.                
    42.     /* Start the timer */
    43.     SCTIMER_StartTimer(SCT0, kSCTIMER_Counter_L);
    44.    
    复制代码

      另配置使用了一个CTIMER0记数匹配中断,用于定时中断更改占空比以改变电机转动的速度。

    1. #define CTIMER CTIMER0                 /* Timer 0 */
    2. #define CTIMER_MAT_OUT kCTIMER_Match_0

    3.    ctimer_config_t config;
    4.     ctimer_match_config_t matchConfig;
    5.      CTIMER_GetDefaultConfig(&config);

    6.     CTIMER_Init(CTIMER, &config);
    7.                
    8.     matchConfig.enableCounterReset =  true;      //mat1 后复位 重记数  控制测量周期
    9.     matchConfig.enableCounterStop = false;//true;//      //mat后不停止
    10.     matchConfig.matchValue = BUS_CLK_FREQ /2000;//200;//0 ;   // BUS_CLK_FREQ/1  即1秒   
    11.     matchConfig.outControl = kCTIMER_Output_NoAction; //无输出关联 
    12.     matchConfig.outPinInitState = false;    // 无效  
    13.     matchConfig.enableInterrupt = true;//       //匹配不中断
    14.     CTIMER_SetupMatch(CTIMER, kCTIMER_Match_1, &matchConfig);   //Timer3 mat1 no out

    15.     CTIMER_RegisterCallBack(CTIMER, &ctimer_callback_table[0], kCTIMER_SingleCallback);//kCTIMER_MultipleCallback);  //kCTIMER_MultipleCallback);  //echo fall intr
    16.                
    17.     CTIMER_StartTimer(CTIMER);   //开始
    复制代码


    中断响应:
    定时中断更改占空比以改变电机转动的速度、方向、LED灯同步指示。
    1)      占空比以小间隔逐渐线性改变, 以实现较平滑的逐渐加减速和反向,而不是突然的改变。
    2)    Port 0的25/26,用分别对应正反转动方向,LED灯亮灭分别对应一个方向的加减速。

    1. void ctimer_match1_callback(uint32_t flags)
    2. {
    3.         if(GorB==1)
    4.         {
    5.                 if(GPIO->B[0][25] ==1)
    6.                 {
    7.                                 PRINTF("\r\n int 1 outpu 0.25  0 \r\n");

    8.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, sp/10+ad, event6);   //  右轮 前进   
    9.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, 1, event7);
    10.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, sp/10, event5); //  左轮 前进               
    11.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, 1, event4);
    12.                         sp +=dsp ;
    13.                         if (sp>upsp)
    14.                                 GPIO->B[0][25] =0;                                      
    15.                 }
    16.                 else
    17.                 {
    18.                                 PRINTF("\r\n int 0 outpu 0.25  1 \r\n");
    19.         /*                SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp, event4);
    20.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); //  左轮 后退
    21.                         
    22.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6);   //  右轮 后退
    23.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp, event7);
    24.         */        
    25.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, sp/10+ad, event6);   //  右轮 前进  +16
    26.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, 1, event7);
    27.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, sp/10, event5); //  左轮 前进
    28.                         
    29.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, 1, event4);
    30.                         
    31.                         
    32.                         sp -=dsp ;
    33.                         if (sp<lwsp)
    34.                         {
    35.                                 GPIO->B[0][25] =1;
    36.                                 GorB=0;
    37.                         }
    38.                 }
    39.         }
    40.         else
    41.                 if(GPIO->B[0][26] ==1)
    42.                 {
    43.                                 PRINTF("\r\n int 1 outpu 0.26  0 \r\n");
    44.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp/10+ad, event7);
    45.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6);   //  右轮 后退 +16
    46.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp/10, event4);
    47.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); //  左轮 后退
    48.                         
    49.                         sp +=dsp ;
    50.                         if (sp>upsp)
    51.                                 GPIO->B[0][26] =0;
    52.                 }
    53.                 else
    54.                 {
    55.                                 PRINTF("\r\n int 0 outpu 0.26  1 \r\n");
    56.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp/10+ad, event7);
    57.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6);   //  右轮 后退 +16
    58.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp/10, event4);
    59.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); //  左轮 后退
    60.                         
    61.                         sp -=dsp ;
    62.                         if (sp<lwsp)
    63.                         {
    64.                                 GPIO->B[0][26] =1;
    65.                                 GorB=1;
    66.                         }
    67.                 }               
    68.         
    69.         
    70. }

    71. ctimer_callback_t ctimer_callback_table[] =
    72. {
    73.     ctimer_match1_callback,//NULL,
    74.     // ctimer_cap_callback,
    75.     NULL,
    76.     NULL,//ctimer_match1_callback,
    77.     NULL,
    78.           NULL,
    79.     //ctimer_cap_callback,
    80.     NULL,
    81.     NULL,
    82.     NULL
    83. };
    复制代码


    注意事项和问题:
    1)   更改占空比实际是在停止和再启SCT之间修改的,四线就这样了4次,应考虑不用库函数代码,在一次停启之间修改四个占空比;
    2)   SCT停止时,只是停的是记数器,有可能某管脚只好PWM处于高电位,这下电机会疯狂旋转!
    3)   不能使用0和100做占空比,这里用的电机驱动不是用独立的线控制正反转方向,所以正反转动方向控制通过把对应2线之一的占空比设为1实现。
    4)   电机通过减速齿轮带动轮子空转,发现旋转阻力不均,不仅占空比与转速不是线性关系,轮子和轴不同角度阻力也不相同(同占空比下转动也不均匀、不太重现)。这还是空转啊,实际岂不是更不均匀了。这个这个我不懂了,可能可能机械转动转动的世界不太理想。也许需要测速反馈控制才能定速控制(这个电机的测速分辨不高,而平衡车是微动,我很怀疑有没用用)。
    5)   带动轮子的空转阻力也不小了,占空比20以下不转,30以上才算转,两个轮子阻力还不一样。
    6)   看这个头重脚轻的东西,严重怀疑这个能否实现平衡车??
    7)   不知道,SCT是否能一个匹配触发多个输出呢?有空再研究吧。
    现在论坛禁止上传视频文件,只好转为动态gif图吧。

    倒置空转,正反转视频:
    我临时使用一个手机电池(7.3V, 3400mAh)经升压模块(已经烧了一个了!)10V供电机驱动。
    VID_20171023_135456_1-_2_.gif


    先悬绳保持,观察正反转视频:(支架用废光盘做的)
    VID_20171023_171947_1_1.gif




    系列:
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2025-1-21 08:52
  • 签到天数: 861 天

    连续签到: 1 天

    [LV.10]以坛为家III

    75

    主题

    2523

    帖子

    24

    金牌会员

    Rank: 6Rank: 6

    积分
    5867
    最后登录
    2025-1-22
    发表于 2017-10-24 10:02:51 | 显示全部楼层
    赞一个
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    连续签到: 1 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5618
    最后登录
    2021-12-22
     楼主| 发表于 2017-10-24 10:15:32 | 显示全部楼层
    谢谢谢谢!

    没搞过电机, 有太多不确定的因素,只好一遍探索猜测一边做了
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 22:51
  • 签到天数: 2477 天

    连续签到: 8 天

    [LV.Master]伴坛终老

    17

    主题

    5350

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    11188
    最后登录
    2025-7-18
    发表于 2017-10-24 20:46:22 | 显示全部楼层
    厉害,赞赞赞!!!!!!!!!
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    连续签到: 1 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5618
    最后登录
    2021-12-22
     楼主| 发表于 2017-10-25 09:34:31 | 显示全部楼层
    怎么后两段代码没了??  晚上回头补上
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-3-22 20:15
  • 签到天数: 21 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    23

    主题

    341

    帖子

    1

    高级会员

    Rank: 4

    积分
    909
    最后登录
    2019-4-7
    发表于 2017-10-25 09:35:25 | 显示全部楼层
    重心有点高啊,能下放就下放吧,
    成功的小小喜悦里,大脑自身可以产生兴奋剂哦!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    连续签到: 1 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5618
    最后登录
    2021-12-22
     楼主| 发表于 2017-10-25 09:42:04 | 显示全部楼层
    噬猎者 发表于 2017-10-25 09:35
    重心有点高啊,能下放就下放吧,

    是啊,正想办法呢,       另板子只有usb供电,怎么接电池也是麻烦, 不行就得加个有些重充电宝了..

    这位老师, 能分享您的平衡车板子的PCB工程吗?
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-3-22 20:15
  • 签到天数: 21 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    23

    主题

    341

    帖子

    1

    高级会员

    Rank: 4

    积分
    909
    最后登录
    2019-4-7
    发表于 2017-10-25 09:50:03 | 显示全部楼层
    okwh 发表于 2017-10-25 09:42
    是啊,正想办法呢,       另板子只有usb供电,怎么接电池也是麻烦, 不行就得加个有些重充电宝了..

    这位老师 ...

    等,我给你发,好久都没来论坛了。你这电机功率不是很高,可以买小四轴用的3.7v锂电池代替。
    成功的小小喜悦里,大脑自身可以产生兴奋剂哦!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-2-14 16:49
  • 签到天数: 296 天

    连续签到: 1 天

    [LV.8]以坛为家I

    241

    主题

    2239

    帖子

    6

    金牌会员

    Rank: 6Rank: 6

    积分
    4473
    最后登录
    2020-4-14
    发表于 2017-11-1 17:24:57 | 显示全部楼层
    非常赞自己动手!但没有理解为什么要用到4路PWM?两只轮子2路PWM就够了,如果是全桥控制,加个非门就有+-对称的PWM了。能说明一下吗?谢谢。尽管没有做平衡小车,但一直在关心着,再次谢谢
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2021-7-5 15:45
  • 签到天数: 664 天

    连续签到: 1 天

    [LV.9]以坛为家II

    42

    主题

    1594

    帖子

    19

    金牌会员

    Rank: 6Rank: 6

    积分
    5618
    最后登录
    2021-12-22
     楼主| 发表于 2017-11-1 20:11:13 | 显示全部楼层
    本帖最后由 okwh 于 2017-11-1 20:14 编辑
    zhjb1 发表于 2017-11-1 17:24
    非常赞自己动手!但没有理解为什么要用到4路PWM?两只轮子2路PWM就够了,如果是全桥控制,加个非门就有+-对 ...

    我买的驱动模块没有独立的前后方向控制。
    每个轮子需要两个IO线,前转时 其中一线为PWM,即 0+PWM,  后转时需要另一线为PWM,即PWM + 0, 
    这样每个轮子要控制前后转就需要两线都能分时有PWM,所以两个轮子共四线,4线都需要PWM.
    前文有逻辑真值表https://www.nxpic.org.cn/module/forum/thread-612473-1-1.html
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-19 14:48 , Processed in 0.114912 second(s), 28 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表