极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 44572|回复: 19

arduino 测速

[复制链接]
发表于 2014-4-18 20:25:11 | 显示全部楼层 |阅读模式
使用是码盘测速,不过对于两个轮子PWM赋值区别很大,可是轮子的
  1. #include <MsTimer2.h>
  2. #define  Value 1.02101761  //计算周长的常量

  3. //volatile int state = HIGH;

  4. int u_left = 2;//定义U型测速端口
  5. int u_right = 3;

  6. int leftCW=4;//连接电机1转向端口到数字接口4
  7. int rightCW=7;//连接电机2转向端口到数字接口7
  8. int leftPWM=5; //连接电机1调速端口到数字接口5     
  9. int rightPWM=6;  //连接电机2调速端口到数字接口6

  10. int r_wheel = 0; //记录U型测速模块的次数
  11. int l_wheel = 0;
  12. float r_velocity=0;//速度;
  13. float l_velocity=0;

  14. float velocity(int n)
  15. {
  16.   //(n/20)轮子装的圈数,轮子直径是65mm
  17.   //速度的计算公式应该为  (n/20)×(65×10-1×π)  即n*1.02101761
  18.   //后面的计算得常数
  19.   float vel =Value*(n/20);
  20.   return vel;
  21. }
  22. void flash()
  23. {//noInterrupts();
  24.   //String s1="";
  25. // String s2="";
  26.   int r,l;
  27.   r=r_wheel;l=l_wheel;
  28.   //noInterrupts();
  29.   r_velocity=velocity(r);
  30.   l_velocity=velocity(l);
  31.   //Serial.print(r_velocity);
  32. // Serial.print("\0");
  33. // itoa (r_wheel,buffer1,10);
  34.   //itoa (l_wheel,buffer2,10);
  35.   //s1+=r;
  36.   //s2+=l;

  37.   Serial.print(l_velocity);
  38.    Serial.print("cm/s(L)");
  39.   Serial.print(" ");
  40.   // Serial.print(l_velocity);
  41.   // Serial.print("\0");
  42.   Serial.print(r_velocity);
  43.    Serial.println("cm/s(R)");
  44.   r_wheel = 0;
  45.   l_wheel = 0;
  46. //  interrupts();
  47. }


  48. void setup ()
  49. {
  50.   Serial.begin(9600);
  51.   
  52.   attachInterrupt(0,RCount, FALLING);
  53.   attachInterrupt(1,LCount, FALLING);
  54.   
  55.   pinMode(leftCW,OUTPUT);
  56.   pinMode(leftPWM,OUTPUT);
  57.   pinMode(rightCW,OUTPUT);
  58.   pinMode(rightPWM,OUTPUT);
  59.   
  60.   MsTimer2::set(1000, flash);        // 中断设置函数,每 1s 进入一次中断
  61.   MsTimer2::start();
  62.   
  63. }

  64. void loop()
  65. {
  66.   digitalWrite( leftPWM,10);//电机1全速前进
  67.   digitalWrite(rightPWM,200);//电机2全速前进
  68.   digitalWrite(leftCW,HIGH);//电机1正转
  69.   digitalWrite(rightCW,HIGH);//电机2正转
  70.   
  71.   while (1)
  72.   {
  73. //   digitalWrite(13, state);
  74.   }
  75.   
  76. }
  77. void LCount()
  78. {
  79.   l_wheel++;
  80. // state=!state;
  81.   
  82. }
  83. void RCount()
  84. {
  85.   r_wheel++;
  86. }


复制代码
速度相差不大,通过串口测试了一下,结果如图,各位大神看一下,有没有问题啊!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2014-4-18 22:54:46 | 显示全部楼层
本帖最后由 Super169 于 2014-4-18 22:59 编辑

少少意見, 由於我沒用過 <MsTimer2.h>, 有些地方想先確認.

MsTimer2::set(1000, flash);

是指每秒執行一次, 而非在第一次執行完一秒後執行, 對嗎?

如果是這樣的話, 重設 l_wheel 及 r_wheel 應盡快進行, 盡可能放最前的位置.
因為 flash 程序執行亦需要時間 (特別是 Serial.print 的部份), 為免影響計算, 在讀取完 r_wheel 及 l_wheel 後即時重設會比較好.

另一個問題是 Arduino 的 interrupt 設計, 當其中一個 interrup 執行中, 另一個 interrupt 好像會被 ignore 的.
現在左右相差很大, 右邊最少有 25% interrupt 遺失了. 假定左邊沒遺失, 右邊比左邊少 25%, 如左邊亦有遺失的話, 實際遺失比例更高.

此外, 亦不太明白你的速度計算, 請問 是否一圈就有 20 格?
如果是的話, 速度不是  (n/20) * (65 * 3.1416) 嗎?  應該是 n * 1.0210
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 00:17:32 | 显示全部楼层
谢谢啊,看你的回复,真心受教了。赋值确实是这样,我处理的不太好。那个速度计算,我在备注这样写的,因为代码有几次改动,所以改着改着就错了。还想请教一下,关于中断ignore,这个改怎么解决呢?或者有其他方法计算码盘的转值。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 00:19:53 | 显示全部楼层
Super169 发表于 2014-4-18 22:54
少少意見, 由於我沒用過 , 有些地方想先確認.

MsTimer2::set(1000, flash);

谢谢啊,看你的回复,真心受教了。赋值确实是这样,我处理的不太好。那个速度计算,我在备注这样写的,因为代码有几次改动,所以改着改着就错了。还想请教一下,关于中断ignore,这个改怎么解决呢?或者有其他方法计算码盘的转值。
回复 支持 反对

使用道具 举报

发表于 2014-4-19 01:30:58 | 显示全部楼层
未知数 发表于 2014-4-19 00:17
谢谢啊,看你的回复,真心受教了。赋值确实是这样,我处理的不太好。那个速度计算,我在备注这样写的,因为 ...

刚开始接触arduino,很多8051有单独的计数器管脚,配置好触发方式就行,不占用系统中断,这个问题就很好解决了,不知道arduino有吗?avr貌似也有
回复 支持 反对

使用道具 举报

发表于 2014-4-19 02:39:35 | 显示全部楼层
未知数 发表于 2014-4-19 00:19
谢谢啊,看你的回复,真心受教了。赋值确实是这样,我处理的不太好。那个速度计算,我在备注这样写的,因 ...

同時有頻密的多個 interrupt, 我也不知 Arduino 是否有解決方法.

樓據網上資料:

Generally, an ISR should be as short and fast as possible. If your sketch uses multiple ISRs, only one can run at a time, other interrupts will be ignored (turned off) until the current one is finished. as delay() and millis() both rely on interrupts, they will not work while an ISR is running. delayMicroseconds(), which does not rely on interrupts, will work as expected.


如果左右同時 觸發, 有可能當中一個會被 ignore.  而且, LCount 及 RCount 也算是 short 了, 但 flash 實在有點長.  我不太肯定 MsTimer2 是否也是經 interrupt 觸發, 如果是的話, 因為執行 flash 而導致 lcount/rcount 失效的機會更大.

如果是 flash 引致就好辦了, 只要把 flash 改成不再由 interrupt 觸發就可以了, 例如放在 loop() 內, 再自行計算兩次讀取計數值的時間差去推算速度.  雖然多了一點計算, 但相信不會是問題.

但如果是因為左右同時觸發, 至導致當中一個失效, 就比較難解決了.

如果有個計數器的模塊自動計數, 無需靠 interrupt 計數, 在 Arduino 中向它發出要求, 回傳及重設數值會比較安全.
回复 支持 反对

使用道具 举报

发表于 2014-4-19 03:38:09 | 显示全部楼层
16位的T/C 可以实现外部事件计数器
Arduino Frequency Counter Library :
http://interface.khm.de/index.ph ... cy-counter-library/
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 09:15:58 | 显示全部楼层
Super169 发表于 2014-4-19 02:39
同時有頻密的多個 interrupt, 我也不知 Arduino 是否有解決方法.

樓據網上資料:
  1. /*
  2. * SimpleTimer.cpp
  3. *
  4. * SimpleTimer - A timer library for Arduino.
  5. * Author: [email protected]
  6. * Copyright (c) 2010 OTTOTECNICA Italy
  7. *
  8. * This library is free software; you can redistribute it
  9. * and/or modify it under the terms of the GNU Lesser
  10. * General Public License as published by the Free Software
  11. * Foundation; either version 2.1 of the License, or (at
  12. * your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will
  15. * be useful, but WITHOUT ANY WARRANTY; without even the
  16. * implied warranty of MERCHANTABILITY or FITNESS FOR A
  17. * PARTICULAR PURPOSE.  See the GNU Lesser General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser
  21. * General Public License along with this library; if not,
  22. * write to the Free Software Foundation, Inc.,
  23. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  24. */


  25. #include "SimpleTimer.h"


  26. SimpleTimer::SimpleTimer() {
  27.     unsigned long current_millis = millis();

  28.     for (int i = 0; i < MAX_TIMERS; i++) {
  29.         enabled[i] = false;
  30.         callbacks[i] = 0;                   // if the callback pointer is zero, the slot is free, i.e. doesn't "contain" any timer
  31.         prev_millis[i] = current_millis;
  32.         numRuns[i] = 0;
  33.     }

  34.     numTimers = 0;
  35. }


  36. void SimpleTimer::run() {
  37.     int i;
  38.     unsigned long current_millis;

  39.     // get current time
  40.     current_millis = millis();

  41.     for (i = 0; i < MAX_TIMERS; i++) {

  42.         toBeCalled[i] = DEFCALL_DONTRUN;

  43.         // no callback == no timer, i.e. jump over empty slots
  44.         if (callbacks[i]) {

  45.             // is it time to process this timer ?
  46.             if (current_millis - prev_millis[i] >= delays[i]) {

  47.                 // update time
  48.                 prev_millis[i] = current_millis;

  49.                 // check if the timer callback has to be executed
  50.                 if (enabled[i]) {

  51.                     // "run forever" timers must always be executed
  52.                     if (maxNumRuns[i] == RUN_FOREVER) {
  53.                         toBeCalled[i] = DEFCALL_RUNONLY;
  54.                     }
  55.                     // other timers get executed the specified number of times
  56.                     else if (numRuns[i] < maxNumRuns[i]) {
  57.                         toBeCalled[i] = DEFCALL_RUNONLY;
  58.                         numRuns[i]++;

  59.                         // after the last run, delete the timer
  60.                         if (numRuns[i] >= maxNumRuns[i]) {
  61.                             toBeCalled[i] = DEFCALL_RUNANDDEL;
  62.                         }
  63.                     }
  64.                 }
  65.             }
  66.         }
  67.     }

  68.     for (i = 0; i < MAX_TIMERS; i++) {
  69.         switch(toBeCalled[i]) {
  70.             case DEFCALL_DONTRUN:
  71.                 break;

  72.             case DEFCALL_RUNONLY:
  73.                 (*callbacks[i])();
  74.                 break;

  75.             case DEFCALL_RUNANDDEL:
  76.                 (*callbacks[i])();
  77.                 deleteTimer(i);
  78.                 break;
  79.         }
  80.     }
  81. }


  82. // find the first available slot
  83. // return -1 if none found
  84. int SimpleTimer::findFirstFreeSlot() {
  85.     int i;

  86.     // all slots are used
  87.     if (numTimers >= MAX_TIMERS) {
  88.         return -1;
  89.     }

  90.     // return the first slot with no callback (i.e. free)
  91.     for (i = 0; i < MAX_TIMERS; i++) {
  92.         if (callbacks[i] == 0) {
  93.             return i;
  94.         }
  95.     }

  96.     // we should never reach this point...
  97.     return -1;
  98. }


  99. int SimpleTimer::setTimer(long d, timer_callback f, int n) {
  100.     int freeTimer;

  101.     freeTimer = findFirstFreeSlot();
  102.     if (freeTimer < 0) {
  103.         return -1;
  104.     }

  105.     delays[freeTimer] = d;
  106.     callbacks[freeTimer] = f;
  107.     maxNumRuns[freeTimer] = n;
  108.     enabled[freeTimer] = true;
  109.     prev_millis[freeTimer] = millis();

  110.     numTimers++;

  111.     return freeTimer;
  112. }


  113. int SimpleTimer::setInterval(long d, timer_callback f) {
  114.     return setTimer(d, f, RUN_FOREVER);
  115. }


  116. int SimpleTimer::setTimeout(long d, timer_callback f) {
  117.     return setTimer(d, f, RUN_ONCE);
  118. }


  119. void SimpleTimer::deleteTimer(int numTimer) {
  120.     if (numTimer >= MAX_TIMERS) {
  121.         return;
  122.     }

  123.     // nothing to delete if no timers are in use
  124.     if (numTimers == 0) {
  125.         return;
  126.     }

  127.     callbacks[numTimer] = 0;
  128.     enabled[numTimer] = false;
  129.     delays[numTimer] = 0;
  130.     numRuns[numTimer] = 0;

  131.     // update number of timers
  132.     numTimers--;
  133. }


  134. // function contributed by [email protected]
  135. void SimpleTimer::restartTimer(int numTimer) {
  136.     if (numTimer >= MAX_TIMERS) {
  137.         return;
  138.     }

  139.     prev_millis[numTimer] = millis();
  140. }


  141. boolean SimpleTimer::isEnabled(int numTimer) {
  142.     if (numTimer >= MAX_TIMERS) {
  143.         return false;
  144.     }

  145.     return enabled[numTimer];
  146. }


  147. void SimpleTimer::enable(int numTimer) {
  148.     if (numTimer >= MAX_TIMERS) {
  149.         return;
  150.     }

  151.     enabled[numTimer] = true;
  152. }


  153. void SimpleTimer::disable(int numTimer) {
  154.     if (numTimer >= MAX_TIMERS) {
  155.         return;
  156.     }

  157.     enabled[numTimer] = false;
  158. }


  159. void SimpleTimer::toggle(int numTimer) {
  160.     if (numTimer >= MAX_TIMERS) {
  161.         return;
  162.     }

  163.     enabled[numTimer] = !enabled[numTimer];
  164. }


  165. int SimpleTimer::getNumTimers() {
  166.     return numTimers;
  167. }
复制代码
这个是MsTimer2的原代码,应该没有用到过中断。arduino本身不含定时计数器中断,上网找过也没有看到什么计数库。所以用的是中断。现在也没什么好办法了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 09:22:38 | 显示全部楼层
hmjack2008 发表于 2014-4-19 03:38
16位的T/C 可以实现外部事件计数器
Arduino Frequency Counter Library :
http://interface.khm.de/index ...

这个默认频率输入端口是5,能不能设置成其他的?我没用过这个库,看介绍还是大概还不太了解,能给指教一下?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 10:03:05 | 显示全部楼层
wangweihe68 发表于 2014-4-19 01:30
刚开始接触arduino,很多8051有单独的计数器管脚,配置好触发方式就行,不占用系统中断,这个问题就很好解 ...

没有吧,arduino就两个外部中断。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 10:05:17 | 显示全部楼层
未知数 发表于 2014-4-19 09:15
这个是MsTimer2的原代码,应该没有用到过中断。arduino本身不含定时计数器中断,上网找过也没有看到什么计 ...

把你说的另外两个问题改了,测试一下,左轮速度比右轮还要快,PWM设置左轮是10,右轮是200,误差应该还是很大。
回复 支持 反对

使用道具 举报

发表于 2014-4-19 11:33:26 | 显示全部楼层
兩個電機的 PWM的推動值區別真的很大,若PWM的推動情況沒問題的話,那麼問題應在電機上了,應檢查一下!
//
  digitalWrite( leftPWM,10);//电机1全速前进
  digitalWrite(rightPWM,200);//电机2全速前进
//
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-4-19 12:51:38 | 显示全部楼层
eddiewwm 发表于 2014-4-19 11:33
兩個電機的 PWM的推動值區別真的很大,若PWM的推動情況沒問題的話,那麼問題應在電機上了,應檢查一下!
/ ...

犯了一个常识性错误,PWM端口应该用analogWrite
回复 支持 反对

使用道具 举报

发表于 2014-4-19 14:00:13 | 显示全部楼层
eddiewwm 发表于 2014-4-19 11:33
兩個電機的 PWM的推動值區別真的很大,若PWM的推動情況沒問題的話,那麼問題應在電機上了,應檢查一下!
/ ...

oh.. 沒留意到有這麼大的分別, 一直以為是等速. 而且是用了 digitalWrite....
回复 支持 反对

使用道具 举报

发表于 2014-11-18 13:53:27 | 显示全部楼层
敢问你是用什么方法来消除干扰的
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-16 19:41 , Processed in 0.041741 second(s), 23 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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