找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 9645|回复: 9
打印 上一主题 下一主题
收起左侧

Arduino智能小车程序+资料 pid算法

  [复制链接]
跳转到指定楼层
楼主
ID:559809 发表于 2019-7-11 15:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include "pid.h"
  2. #ifdef ARDUINO_DEBUG
  3. int debugLeftSpeed;
  4. int debugRightSpeed;
  5. uint8_t debugIrs = 0;
  6. #endif
  7. const float motorSpeed = 140; //
  8. const int IR_PIN[] = {A0, A1, A2, A3, A4}; //
  9. const int IN_A1 = 13;   //
  10. const int IN_A2 = 12;   //
  11. const int IN_B1 = 11;  //
  12. const int IN_B2 = 10;  //
  13. const int _pwmLeftPin = 5;
  14. const int _pwmRightPin = 6;
  15. pid_t pid;
  16. float pidValue = 0;
  17. bool turnFlag = false;
  18. void setup(void)
  19. {
  20.   int i;
  21.   /********************1.初始化电机模块引脚13,12,11,10为输出模式******************/
  22.   /*
  23.    *   编写代码
  24.   */
  25.     /********************2.设置小车启动速度为140---set_speed()******************/
  26.   /*
  27.    *   编写代码
  28.   */
  29.   
  30.   /********************3.初始化循迹模块引脚A0, A1, A2, A3, A4为输入模式******************/
  31.    /*
  32.    *   编写代码
  33.   */
  34.   //3.设置PID参数
  35.   pid.sampleTime = SAMPLE_TIME;
  36.   pid.Kp = KP_VALUE;
  37.   pid.Ki = KI_VALUE;
  38.   pid.Kd = KD_VALUE;
  39.   pid.error = 0;
  40.   pid.previous_error = 0;
  41.   Serial.begin(115200);
  42.   delay(5000);
  43.   goForward();
  44.   return;
  45. }

  46. //get ir data and middle filter
  47. uint8_t getIrData(void)  //
  48. {
  49.   int i, j;
  50.   uint8_t level;
  51.   uint8_t temp;
  52.   uint8_t irs[9] = {0};//采集9次传感器的传感器的数据
  53.         //减少取平均值,滤波。
  54.   for (j = 0; j < 9; j ++) {
  55.    
  56.       for (i = 0; i < 5; i++) {
  57.         level = digitalRead(IR_PIN[i]);
  58.         if (level) {
  59.           bitSet(irs[j], i); // 设置irs[j]的第jbit 为1
  60.         } else {
  61.           bitClear(irs[j], i); //清除irs[j]的第jbit为0
  62.         }
  63.       }
  64.   }
  65.   //对irs中的数据,进行9次排序,取最中间的值。
  66.   for (i = 0; i < 9 - 1; i ++) {
  67.     for (j = 0; j < 9 - i - 1; j ++) {
  68.       if (irs[j] > irs[j + 1]) {
  69.         temp = irs[j];
  70.         irs[j] = irs[j + 1];
  71.         irs[j + 1] = temp;
  72.       }
  73.     }
  74.   }
  75.   
  76. #ifdef ARDUINO_DEBUG
  77.   debugIrs = irs[4];
  78. #endif
  79.   return irs[4];
  80. }
  81. int calcErrorByIrsValue(uint8_t irs)
  82. {
  83.   //右边压线为负,左边压线为正。
  84.   //要左转为负,要右转为正
  85.   int curError = pid.error; //获得上一次的pid误差值
  86.   //压线输出低电平0,没有压线输出高电平1
  87.   switch (irs) { //h'h
  88.     case B11110: curError = -8; break; //最右边压线
  89.    
  90.     case B10000:
  91.     case B11000: curError = -7; break; //右四个或者右3个沿线
  92.    
  93.     case B11100: curError = -6; break; //右两个沿线
  94.     case B11101: curError = -4; break; //右倒数第二个沿线
  95.     case B11001: curError = -2; break; //
  96.    
  97.     case B00000:       //全部压线和中间压线,对应"十字"弯道,直接郭即可。
  98.     case B11011: curError = 0;  break;
  99.    
  100.     case B10011: curError = 2;  break;
  101.     case B10111: curError = 4;  break;
  102.     case B00111: curError = 6;  break;
  103.    
  104.     case B00011:
  105.     case B00001: curError = 7;  break;
  106.    
  107.     case B01111: curError = 8;  break;
  108. //都没有沿线,按照上次的PID值来计算
  109.     case B11111: curError = pid.error > 0 ? 9 : - 9; break;
  110.   }
  111.   return curError;
  112. }

  113. void _sortData(int *p, int n)
  114. {
  115.   int temp;
  116.   int i, j;
  117.   
  118.   /**编写冒泡排序,对采集到的错误码,进行十次从小到大排序 **/
  119.   /*
  120.    *   编写代码
  121.   */
  122.   return;
  123. }

  124. //计算当前的误差值,得到当前的偏移值
  125. void calcCurrentError(void)
  126. {
  127.   int i;
  128.   uint8_t irs;
  129.   float sum = 0;
  130.   int errorData[10];
  131.   //1.采集10次循迹模块获得的错误码
  132.   for (i = 0; i < 10; i ++) {
  133.     irs =  getIrData();  //得到这次传感器采集的数据(5路数据)
  134.     errorData[i] =  calcErrorByIrsValue(irs);
  135.   }
  136.   //2.要求对errorData中的数据进行排序(从小到大排序)
  137.     /*
  138.    *   编写代码
  139.   */
  140.   //3.十次中去处一个最高数,去除一个最低数,求中间8次错误码数据的和。
  141.   /*
  142.    *   编写代码
  143.   */
  144. //4.求8次错误码数据中的偏差。
  145.   pid.error = sum / 8;
  146.   return;
  147. }
  148. void turnRight(void)
  149. {
  150.     digitalWrite(IN_B1, HIGH); //左正
  151.     digitalWrite(IN_B2, LOW);
  152.     digitalWrite(IN_A1, LOW); //右反
  153.     digitalWrite(IN_A2, HIGH);
  154.    
  155. }
  156. void turnLeft(void)
  157. {
  158.     digitalWrite(IN_B1, LOW);// 左反
  159.     digitalWrite(IN_B2, HIGH);
  160.     digitalWrite(IN_A1, HIGH); //右正
  161.     digitalWrite(IN_A2, LOW);
  162.    
  163. }
  164. void goForward(void)
  165. {
  166.   digitalWrite(IN_B1, HIGH); //左正传
  167.   digitalWrite(IN_B2, LOW);
  168.   digitalWrite(IN_A1, HIGH); //右正转
  169.   digitalWrite(IN_A2, LOW);
  170. }
  171. void motorControl(float pidValue, bool turnFlag)
  172. {
  173.   int leftMotorSpeed = 0;
  174.   int rightMotorSpeed = 0;
  175.   
  176.   leftMotorSpeed  = constrain((motorSpeed + pidValue), -255, 255);
  177.   rightMotorSpeed = constrain((motorSpeed - pidValue), -255, 255);
  178.   if (turnFlag) {
  179.     if (abs(leftMotorSpeed) > abs(rightMotorSpeed)) {
  180.       leftMotorSpeed  = abs(leftMotorSpeed);
  181.       rightMotorSpeed = leftMotorSpeed;
  182.     } else {
  183.       rightMotorSpeed =  abs(rightMotorSpeed);
  184.       leftMotorSpeed  = rightMotorSpeed;
  185.     }
  186.   } else {
  187.     leftMotorSpeed  = leftMotorSpeed  > 0 ? leftMotorSpeed  : -leftMotorSpeed;
  188.     rightMotorSpeed = rightMotorSpeed > 0 ? rightMotorSpeed : -rightMotorSpeed;
  189.   }
  190.   analogWrite(_pwmLeftPin,  leftMotorSpeed );
  191.   analogWrite(_pwmRightPin, rightMotorSpeed);
  192. #ifdef ARDUINO_DEBUG
  193.   debugLeftSpeed  = leftMotorSpeed ;
  194.   debugRightSpeed = rightMotorSpeed;
  195. #endif
  196.   return;
  197. }
  198. bool calculatePid(float *pValue)
  199. {
  200.   float P = 0;
  201.   static float I = 0 ;
  202.   float D = 0 ;
  203.   static unsigned long lastTime = 0;
  204.   //获得机器从启动到现在所运行的时间
  205.   unsigned long now = millis();
  206.   int timeChange = now - lastTime;//得到这次的时间
  207.   //若是我们的这次变化的时间,小于pid的
  208.   //采样时间,就需要等待一下。
  209.   if (timeChange < pid.sampleTime) {
  210.     return false;
  211.   }
  212.   P = pid.error; //本次小车传感器的偏移大小
  213.   I = I + pid.error;//历史的偏移
  214.   D = pid.error - pid.previous_error; //最近两次的差值
  215.   *pValue = (pid.Kp * P) + (pid.Ki * I) + (pid.Kd * D) + 1;
  216.   //constrain()函数的功能:若是*pvalue > motorSpeed,取 motorSpeed,
  217.   //                       若是*pvalue < -motorSpeed,取 -motorSpeed,
  218.   //        若是-pValue<=*pvalue <= motorSpeed,取*pvalue
  219.   *pValue = constrain(*pValue, -motorSpeed,motorSpeed);
  220.   pid.previous_error = pid.error; //记录本次的pid.error,作为下一次的历史差值。
  221.   lastTime = now; // 记录本次的运行时间,作为下一次时间的历史时间参考。
  222.   return true;
  223. }

  224. void calcDirection(void) //判断小车的转向
  225. {
  226.   //pid.error > 0 说明小车左边压线多,要
  227.   if (pid.error >= 7 && pid.error <= 8) {
  228.     turnRight();
  229.     turnFlag = true;
  230.   } else if (pid.error >= -8 && pid.error <= -7) {
  231.     turnLeft();
  232.     turnFlag = true;
  233.   } else if(pid.error == 9 || pid.error == -9){
  234.     turnRight();
  235.     turnFlag = true;
  236.     }else {
  237.     goForward();
  238.     turnFlag = false;
  239.   }
  240.   return;
  241. }
  242. void loop(void)
  243. {
  244.   bool ok;
  245.   float  pidValue;
  246.   calcCurrentError();
  247.   ok = calculatePid(&pidValue); //计算当前pid的差值。,若是就绪了
  248.   if (ok) {
  249.     calcDirection();
  250.     motorControl(pidValue, turnFlag);
  251.   }
  252.   return;
  253. }
复制代码

pid_student.zip

3.1 KB, 下载次数: 148, 下载积分: 黑币 -5

Arduino 智能小车 - 寻迹.pdf

322.06 KB, 下载次数: 149, 下载积分: 黑币 -5

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏18 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
ID:560595 发表于 2019-7-16 13:46 | 只看该作者
这个要顶
回复

使用道具 举报

板凳
ID:505027 发表于 2019-7-16 21:26 | 只看该作者
这个好,记录一下
回复

使用道具 举报

地板
ID:594846 发表于 2019-8-4 22:31 | 只看该作者
真好,赞一个!
回复

使用道具 举报

5#
ID:609660 发表于 2019-9-9 19:22 来自手机 | 只看该作者
这个资源确实好
回复

使用道具 举报

6#
ID:149774 发表于 2019-9-21 21:44 | 只看该作者
做个记号,回头学习一下
回复

使用道具 举报

7#
ID:614623 发表于 2019-9-22 00:16 | 只看该作者
这个可以参考
回复

使用道具 举报

8#
ID:652804 发表于 2019-12-15 15:42 | 只看该作者
谢谢,学习学习。
回复

使用道具 举报

9#
ID:28942 发表于 2020-9-15 19:24 | 只看该作者
编辑不过是什么原因?
回复

使用道具 举报

10#
ID:1011808 发表于 2022-4-5 13:47 | 只看该作者
arduino如何设置小车启动速度
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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