飞道的博客

江苏省工程训练赛--物料搬运小车(附代码)

541人阅读  评论(0)

        程序和方案还有很多要改进的地方,自己以后也没有机会再做这个比赛了,当时自己苦思冥想的东西,如果能帮助到需要的人,那就再次发挥了价值!也很希望大家比完赛后,能分享自己的思考,想法和方案。

================================================================

                     比赛视频,大神勿喷https://www.bilibili.com/video/av49807687

================================================================

          一开始我并不知道要参加这个比赛(老师偷偷给我报名了-_-!!),后来期末考试考完了,在楼下洗澡碰到实验室的同学,他说:“你是不是有一个比赛要参加”。我当时一脸懵逼,第二天老师就通知去实验室集合,说是有新项目。。。。。。

        我们是第一次参加这个比赛项目,没啥经验,心里也没底,当时听完比赛规则,感觉还是挺简单的。(这种比赛项目难的不是做出来,而是做好,因为你不可能考虑到所有情况,比赛场地,光线啥的影响很大!!就算你在家里调试好了,到了比赛的地方,可能又会出现新问题,所以调试是最难的。)

        我们是三月初开始做的,每天都花很多的时间在这上面,因为完全从零开始做,毫无头绪。比赛的内容听起来很简单,就是读取任务,然后按照任务顺序,抓取物块,放置到规定的地方。涉及到,电机控制,二维码读取,和一个路径的自主判断等,代码部分的主要难点在于各个模块之间的配合。特别是寻迹模块(黑标)与底盘的配合真的搞得头都大了!整个代码逻辑写出来做出来不难,就是细节很多,调试很麻烦,真的很麻烦!

        而且这个比赛还有焊接电路版和拆装的环节,整个比赛我们一直处在疲于奔命的状态,我们负责装配的同学差点被逼疯了,田大头装机械臂的时候手都在抖,一边装一边骂(+_+!)。电路板在设计的时候可以把主控芯片和晶振分离出来,采用插拔式,这样焊接电路板会很省时间,只要焊接一个主控就好了,不然真的焊不完,就算焊完了几乎也用不了。。。

        我们的方案是步进电机加麦克纳姆轮(超级稳(慢)的那种 ),但是寻迹做的不太好(黑标受光线影响太大!!!),底盘的运动速度不是很快,害怕速度给快了抖动(会飘)。

       物块抓取是两块控制板通信。我们用了两块Arduino mega2560控制板,一块运行舵机控制程序,控制机械臂抓取物块,一块运行主程序,颜色识别是TCS230模块,二维码用的是二维码识别模块(微雪)。

        整个项目思路得细节方面还是看代码吧,能注释的地方都注释了,变量命名也是有规律的(一个一个单词查的),一般是可以看懂的,这样可以直接理解思路!

        下面是全部的代码(代码打包了,需要可以自取,和下面一样的)。

================================================================

           程序重新打包了一下:

                            https://wwa.lanzous.com/i1Je0mxt86d 密码:6k6y

           用到的其他库: 

                           https://www.lanzous.com/i6rju8f 密码:atk3

================================================================

 

舵机控制程序:


  
  1. #include <SerialCommand.h> //字符串处理库函数
  2. #include <Servo.h> //舵机控制库
  3. SerialCommand SCmd; //定义字符处理对象
  4. Servo myservo[ 3]; //定义舵机控制对象
  5. //#define DEBUG1
  6. //#define DEBUG
  7. /*---------------舵机抓取角度宏定义------------*/
  8. //上部舵机角度
  9. //BEGIN:开始状态
  10. //CATCH : 抓取角度
  11. //PUT : 放置角度
  12. //DCATCH : 待抓取角度
  13. #define SERVO_S_BEGIN 57
  14. #define SERVO_S_CATCH 0
  15. #define SERVO_S_PUT 20
  16. #define SERVO_S_DCATCH 40
  17. //中间舵机角度
  18. //BEGIN : 开始角度
  19. //CATCH : 夹取角度
  20. #define SERVO_Z_BEGIN 25
  21. #define SERVO_Z_CATCH 89 //斜一点居中
  22. //底部角度
  23. //MIDDLE : 中间角度
  24. //PUT : 放置角度
  25. //CATCH: 夹取角度
  26. #define SERVO_X_MIDDLE 90
  27. #define SERVO_X_PUT 20
  28. #define SERVO_X_CATCH 150
  29. /*----------------模式定义--------------------*/
  30. #define BEGIN_MODEL 0
  31. #define MIDDLE_MODEL 1
  32. #define DCATCH_MODEL 2
  33. #define CATCH_MODEL 3
  34. #define PUT_MODEL 4
  35. #define DPUT_MODEL 5
  36. #define DMIDDLE_MODEL 6
  37. //新添
  38. #define _CATCH 7
  39. #define _PUT 8
  40. /*----------------舵机端口设置----------------*/
  41. int servo_port[ 3] = { 3, 8, 12}; //舵机端口 从上到下
  42. /*-----------------舵机初始角度---------------*/
  43. float servo_angle[ 3] = { 40, 25, 90}; //舵机端口 从上到下
  44. void setup() {
  45. Serial.begin( 9600); //启动串口
  46. SCmd.addCommand( "T", control_model);
  47. //舵机初始化函数
  48. servoInti();
  49. #ifdef DEBUG1 // DEBUG1
  50. beginModel();
  51. dmiddleModel();
  52. catchModel();
  53. putModel();
  54. dputModel();
  55. dcatchModel();
  56. middleModel();
  57. #endif
  58. #ifdef DEBUG // DEBUG
  59. // beginModel();
  60. // _catch();
  61. // _put();
  62. #endif
  63. beginModel();
  64. }
  65. void loop() {
  66. SCmd.readSerial(); //循环读取外部数值
  67. }
  68. //舵机初始化函数
  69. void servoInti() {
  70. for ( int i = 0; i < 3; i++) {
  71. myservo[i].attach(servo_port[i]); //舵机端口连接
  72. myservo[i].write(servo_angle[i]); //运动到舵机初始角度
  73. }
  74. }
  75. //控制模式
  76. void control_model() {
  77. char *arg; //字符指针
  78. int action_model; //控制模式匹配
  79. arg = SCmd.next(); //读取控制模式
  80. action_model = atoi(arg);
  81. switch (action_model) {
  82. case BEGIN_MODEL:
  83. beginModel();
  84. break;
  85. case CATCH_MODEL:
  86. catchModel();
  87. break;
  88. case PUT_MODEL:
  89. putModel();
  90. break;
  91. case MIDDLE_MODEL:
  92. middleModel();
  93. break;
  94. case DCATCH_MODEL:
  95. dcatchModel();
  96. break;
  97. case DPUT_MODEL:
  98. dputModel();
  99. break;
  100. case DMIDDLE_MODEL:
  101. dmiddleModel();
  102. break;
  103. case _CATCH:
  104. _catch();
  105. break;
  106. case _PUT:
  107. _put();
  108. break;
  109. default:
  110. break;
  111. }
  112. }
  113. //开始姿态控制
  114. inline void beginModel(){
  115. myservo[ 0].write(SERVO_S_BEGIN);
  116. delay( 1000);
  117. myservo[ 1].write(SERVO_Z_BEGIN);
  118. delay( 1000);
  119. myservo[ 2].write(SERVO_X_MIDDLE);
  120. delay( 1000);
  121. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  122. }
  123. //中立准备姿态控制
  124. inline void dmiddleModel(){
  125. myservo[ 0].write(SERVO_S_DCATCH);
  126. delay( 1000);
  127. myservo[ 1].write(SERVO_Z_CATCH);
  128. delay( 1000);
  129. myservo[ 2].write(SERVO_X_MIDDLE);
  130. delay( 1000);
  131. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  132. }
  133. //抓取姿态控制
  134. inline void catchModel(){
  135. myservo[ 0].write(SERVO_S_CATCH);
  136. delay( 1000);
  137. myservo[ 1].write(SERVO_Z_CATCH);
  138. delay( 1000);
  139. myservo[ 2].write(SERVO_X_CATCH);
  140. delay( 1000);
  141. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  142. }
  143. //放置姿态控制
  144. inline void putModel(){
  145. myservo[ 0].write(SERVO_S_DCATCH);
  146. delay( 1000);
  147. myservo[ 1].write(SERVO_Z_CATCH);
  148. delay( 1000);
  149. myservo[ 2].write(SERVO_X_PUT);
  150. delay( 1000);
  151. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  152. }
  153. //待放置姿态控制
  154. inline void dputModel(){
  155. myservo[ 0].write(SERVO_S_CATCH);
  156. delay( 1000);
  157. myservo[ 1].write(SERVO_Z_CATCH);
  158. delay( 1000);
  159. myservo[ 2].write(SERVO_X_PUT);
  160. delay( 1000);
  161. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  162. }
  163. //待抓取姿态控制
  164. inline void dcatchModel(){
  165. myservo[ 0].write(SERVO_S_DCATCH);
  166. delay( 1000);
  167. myservo[ 1].write(SERVO_Z_CATCH);
  168. delay( 1000);
  169. myservo[ 2].write(SERVO_X_CATCH);
  170. delay( 1000);
  171. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  172. }
  173. //中立抓取姿态控制
  174. inline void middleModel(){
  175. myservo[ 0].write(SERVO_S_CATCH);
  176. delay( 1000);
  177. myservo[ 1].write(SERVO_Z_CATCH);
  178. delay( 1000);
  179. myservo[ 2].write(SERVO_X_MIDDLE);
  180. delay( 1000);
  181. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  182. }
  183. //抓
  184. inline void _catch() {
  185. //中立张开
  186. myservo[ 1].write(SERVO_Z_CATCH);
  187. delay( 1000);
  188. //待抓
  189. myservo[ 2].write(SERVO_X_CATCH);
  190. delay( 1000);
  191. //抓
  192. myservo[ 0].write(SERVO_S_CATCH);
  193. delay( 1000);
  194. //中立抓取
  195. myservo[ 2].write(SERVO_X_MIDDLE);
  196. delay( 1000);
  197. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  198. }
  199. //放
  200. inline void _put() {
  201. // dputModel();//待放
  202. myservo[ 2].write(SERVO_X_PUT);
  203. delay( 1000);
  204. //轻放
  205. myservo[ 0].write( 17);
  206. delay( 2000);
  207. // putModel();//全放
  208. myservo[ 0].write(SERVO_S_DCATCH);
  209. delay( 1000);
  210. // dmiddleModel();//中立张开
  211. myservo[ 2].write(SERVO_X_MIDDLE);
  212. delay( 1000);
  213. //Serial.println("Y");//反馈给2560,表明动作执行完毕
  214. }

主程序:


  
  1. /******************************************************
  2. OLED屏幕 :
  3. 128 个像素横向排列在 X 轴上,分别以 0-127 来代表,
  4. 64个像素垂直排列在 Y 轴上,分别以 0-63 来代表。
  5. ******************************************************/
  6. #include <Arduino.h>
  7. #include <Wire.h>
  8. #include "scanner.h"
  9. #include <U8g2lib.h>
  10. #define PUTORDER "123" //物料放置时从左至右为红,绿,蓝,对应序号为123
  11. //物料放置时从左至右为蓝,绿,红,对应序号为321
  12. enum Dir {X = 1, _X = 2, Y = 3, _Y = 4}; //延时寻迹用
  13. /*=====================传感器端口设置==================*/
  14. int S_FL = A0; //车头左侧传感器
  15. int S_FR = A1; //车头右侧传感器
  16. int S_LF = A5; //左侧前传感器
  17. int S_LB = A4; //左侧后传感器
  18. int S_RF = A3; //右前侧传感器
  19. int S_RB = A2; //右后侧传感器
  20. int S_BL = A15; //后左侧传感器
  21. int S_BR = A11; //后右侧传感器
  22. /*====================小车行驶的速度==================*/
  23. float linear_v = 0.2; //速度控制
  24. float runingSpeed= 0.2; //前进速度
  25. /*====================次序存储=======================*/
  26. String qr_data = ""; //存储二维码顺序
  27. String color_data = ""; //存储颜色顺序
  28. String get_data = ""; //存储抓取顺序
  29. int get_order[ 3]; //存储抓取顺序
  30. int put_order[ 3]; //存储放置顺序
  31. int count = 0; //Y向黑线计数
  32. /*======================定义OLED对象=================*/
  33. U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
  34. /*===========定义二维码扫描对象和颜色扫描对象==========*/
  35. Scanner myScanner0; //二维码
  36. Scanner myScanner1; //颜色
  37. /*=================Arduino初始化函数================*/
  38. void setup() {
  39. Serial.begin( 9600);
  40. Serial1.begin( 9600); //二维码反馈端口
  41. Serial2.begin( 9600); //舵机通信
  42. //引脚端口初始化
  43. pinMode(S_FL, INPUT);
  44. pinMode(S_FR, INPUT);
  45. pinMode(S_LF, INPUT);
  46. pinMode(S_LB, INPUT);
  47. pinMode(S_RF, INPUT);
  48. pinMode(S_RB, INPUT);
  49. pinMode(S_BL, INPUT);
  50. pinMode(S_BR, INPUT);
  51. /*--------------OLED初始化----------------*/
  52. ledInti();
  53. /*-------------构建Scanner扫描对象--------*/
  54. myScanner0.setType( 0); //类型 0 为构建二维码扫描对象
  55. myScanner1.setType( 1); //类型 1 为构建颜色扫描对象
  56. /*------------步进电机初始化--------------*/
  57. intiMotors();
  58. /*---------------等待触发开始-------------*/
  59. //wait(); //端口为A10的触发传感器触发开始
  60. /*----------------步骤1-------------------*/
  61. stepOne();
  62. /*----------------步骤2-------------------*/
  63. stepTwo();
  64. /*----------------步骤3-------------------*/
  65. stepThree();
  66. /*----------------步骤4-------------------*/
  67. stepFour();
  68. }
  69. /*--------------------------------------*
  70. Arduino循环函数
  71. --------------------------------------*/
  72. void loop() {
  73. }
  74. /*--------------------------------------*
  75. 步骤一:离开出发区
  76. --------------------------------------*/
  77. void stepOne() {
  78. //穿门
  79. moveTo( 0.35, 0, 3); //向Y正方向平移出出发区
  80. //舵机到待抓中立位置
  81. servoMiddle();
  82. moveTo( 0.215, 0, 1); //向X方向平移0.23米
  83. while (toDigital(S_FL) && toDigital(S_BL)) moveTo( 0.001, 0, 4); //移动至黑线处
  84. delay( 200);
  85. }
  86. /*--------------------------------------*
  87. 步骤二:识别二维码和颜色
  88. --------------------------------------*/
  89. void stepTwo() {
  90. const double dx = 0.24; //中部传感器触发时,颜色传感器到第一个物块的距离
  91. while ( 1) {
  92. if (count < 5) {
  93. if (!toDigital(S_LB)) { //传感器触发,计数
  94. count++;
  95. while (!toDigital(S_LB)) moveTo( 0.001, 0, 1); //将左前触发传感器,脱离触发黑线
  96. switch (count) {
  97. case 2:
  98. //左后传感器触发两次后,移动到第一个物块,进行颜色识别
  99. moveTo(dx, 0, 1);
  100. stopHalSec(); //停止
  101. colorDetect( 0); //第一次检测颜色
  102. break;
  103. case 3:
  104. //左后传感器触发三次后,移动到第二个物块,进行颜色识别
  105. moveTo( 0.09, 0, 1);
  106. stopHalSec();
  107. colorDetect( 1); //第二次检测颜色
  108. break;
  109. default: break;
  110. }
  111. } else {
  112. trackingX(); //X正方向寻迹
  113. }
  114. } else {
  115. //到达二维码区域
  116. //扫描二维码,获取二维码数据
  117. moveTo( 0.035, 0, 2); //修正二维码扫描的位置
  118. qrDetect(); //二维码扫描
  119. delay( 100);
  120. //扫描完成
  121. break;
  122. }
  123. }
  124. }
  125. /*--------------------------------------*
  126. 步骤三:抓取放置
  127. --------------------------------------*/
  128. void stepThree() {
  129. //调试用
  130. //color_data = "321";
  131. //qr_data = "321";
  132. GetOrderDisplay(qr_data); //抓取顺序显示);//抓取顺序显示
  133. //通过颜色识别与二维码要求信息比对,获取抓取顺序
  134. for ( int i = 0; i < qr_data.length(); i++) {
  135. for ( int j = 0; j < color_data.length(); j++) {
  136. if (qr_data[i] == color_data[j]) {
  137. get_data += j; //通过比对设置抓取顺序
  138. }
  139. }
  140. }
  141. //设置抓取顺序数组
  142. GetOrderSet(get_data); //将字符串转化为数字存入抓取数组
  143. //设置放置顺序数组
  144. PutOrderCalc(); //将字符串转化为数字存入放置数组
  145. //后退
  146. moveTo( 0.05, 0, 2); //向后退一小段距离让左后传感器离开黑线
  147. delay( 20);
  148. //后退到中心位置区
  149. int count = 0;
  150. while ( 1) {
  151. if (count < 2) {
  152. if (!toDigital(S_LB)) { //传感器触发,计数
  153. count++;
  154. while (!toDigital(S_LB)) moveTo( 0.001, 0, 2); //将左前触发传感器,脱离触发黑线
  155. } else {
  156. tracking_X(); //向后寻迹
  157. }
  158. } else {
  159. stopHalSec(); //左前传感器触碰到两条黑线立即停止
  160. break;
  161. }
  162. }
  163. //调试看是否需要调整位置
  164. //开始根据抓取数组判断抓取顺序
  165. for ( int i = 0; i < 3; i++) {
  166. //抓取
  167. switch (get_order[i]) {
  168. case 0: //抓取位置一
  169. moveTo( 0.16, 0, 2); // 移动到位置一物块处
  170. getT( 0);
  171. while (toDigital(S_LB) && toDigital(S_RB)) moveTo( 0.001, 0, 1);
  172. //调整车身
  173. break;
  174. case 1: //抓取位置二
  175. //moveTo(0.01, 0, 1); //位置调整
  176. getT( 1);
  177. break;
  178. case 2: //抓取位置三
  179. moveTo( 0.16, 0, 1); //移动到位置三处
  180. getT( 2);
  181. while (toDigital(S_LF) && toDigital(S_RF)) moveTo( 0.001, 0, 2); //是否可用升级版延时寻迹?????
  182. //调整车身
  183. break;
  184. }
  185. //放置
  186. switch (put_order[i]) {
  187. //位置确定方法,从左到右
  188. case 0: putT( 0); break; //放置到位置一
  189. case 1: putT( 1); break; //放置到位置二
  190. case 2: putT( 2); break; //放置到位置三
  191. }
  192. }
  193. }
  194. /*--------------------------------------*
  195. 步骤四:返回出发区
  196. --------------------------------------*/
  197. void stepFour() {
  198. int count = 0;
  199. //调整车身远离中心黑线
  200. moveTo( 0.08, 0, 2);
  201. linear_v = runingSpeed; //速度设置为 0.3m/s
  202. while (count != 3) {
  203. if (count < 3) {
  204. if (!toDigital(S_LF)) {
  205. count++;
  206. while (!toDigital(S_LF)) moveTo( 0.001, 0, 2);
  207. }
  208. else {
  209. tracking_X(); //向后循迹
  210. //moveTo(0.001, 0, 2);
  211. }
  212. }
  213. }
  214. //返回开始区域
  215. moveTo( 0.15, 0, 2);
  216. moveTo( 0.20, 0, 4);
  217. /*********************/
  218. //lcdClear();
  219. //u8g2.drawStr(15, 3, "Mission Complete!");
  220. //u8g2.sendBuffer();//将缓存输出到屏幕
  221. /*********************/
  222. }
  223. /*-------------------------------------*
  224. OLED屏幕的初始化
  225. -------------------------------------*/
  226. void ledInti() {
  227. u8g2.begin();
  228. u8g2.clearBuffer(); //清除模组的缓存
  229. u8g2.setFont(u8g2_font_ncenB14_tr); // 设置字体
  230. delay( 200);
  231. }
  232. /*--------------------------------------*
  233. 二维码扫描函数
  234. --------------------------------------*/
  235. void qrDetect() {
  236. myScanner0.scan(); //会一直读取知道得到二维码顺序
  237. qr_data = myScanner0.getData();
  238. }
  239. /*--------------------------------------*
  240. 触碰传感器等待触发
  241. --------------------------------------*/
  242. /*
  243. void wait() {
  244. u8g2.drawStr(30, 1, "waiting...");
  245. u8g2.sendBuffer(); // 将缓存输出到屏幕
  246. while(toDigital(S_Begin)) delay(1); //等待触发
  247. lcdClear();
  248. u8g2.drawStr(0, 0, "begin!");
  249. u8g2.sendBuffer(); // 将缓存输出到屏幕
  250. }
  251. */
  252. /*--------------------------------------*
  253. 颜色检测函数
  254. --------------------------------------*/
  255. void colorDetect(int i) {
  256. switch (i) {
  257. case 0: myScanner1.scan(); break;
  258. case 1: myScanner1.scan(); break;
  259. }
  260. color_data = myScanner1.getData();
  261. }
  262. /*-------------------------------------*
  263. 抓取顺序计算
  264. -------------------------------------*/
  265. void GetOrderSet(String str) {
  266. int n = str.toInt(); //字符串转化为整数型
  267. get_order[ 0] = n / 100 % 10; //取第一个数字
  268. get_order[ 1] = n / 10 % 10; //取第二个数字
  269. get_order[ 2] = n % 10; //取第三个数字
  270. }
  271. /*--------------------------------------*
  272. 放置顺序计算
  273. --------------------------------------*/
  274. void PutOrderCalc() {
  275. String str = PUTORDER; //物料放置时从左至右为红,绿,蓝,对应序号为123
  276. for ( int i = 0; i < qr_data.length(); i++) {
  277. for ( int j = 0; j < 3; j++) {
  278. if (qr_data[i] == str[j])
  279. put_order[i] = j;
  280. }
  281. }
  282. }
  283. /*-------------------------------------*
  284. 抓取函数
  285. -------------------------------------*/
  286. void getT(int i) {
  287. linear_v = 0.1; //设置车身校准速度
  288. //校准车身的位置
  289. switch (i) {
  290. case 0: moveTo( 0.03, 0, 3); break; //位置一物块抓取校准
  291. case 1: moveTo( 0.03, 0, 3); break; //位置二物块抓取校准
  292. case 2: moveTo( 0.03, 0, 3); break; //位置三物块抓取校准
  293. }
  294. linear_v = runingSpeed; //速度设置
  295. servoCatch();
  296. //校准车身的位置
  297. switch (i) {
  298. case 0: moveTo( 0.03, 0, 4); break; //位置一物块抓取校准
  299. case 1: moveTo( 0.03, 0, 4); break; //位置二物块抓取校准
  300. case 2: moveTo( 0.03, 0, 4); break; //位置三物块抓取校准
  301. }
  302. }
  303. /*-----------------------------------------*
  304. 放置函数调用
  305. -----------------------------------------*/
  306. void putSet(int i) {
  307. delayTracking(Y, 5); //延时寻迹越过两条线
  308. //至物料放置区
  309. while (toDigital(S_LF) || toDigital(S_LB)) trackingY(); //moveTo(0.001,0,3);//
  310. //位置调整
  311. switch (i) {
  312. case 0: moveTo( 0, 0, 0); break;
  313. case 1: moveTo( 0, 0, 0); break;
  314. case 2: moveTo( 0, 0, 0); break;
  315. }
  316. //放置
  317. servoPut();
  318. //返回位置调整
  319. switch (i) {
  320. case 0: moveTo( 0, 0, 0); break;
  321. case 1: moveTo( 0, 0, 0); break;
  322. case 2: moveTo( 0, 0, 0); break;
  323. }
  324. //返回
  325. delayTracking(_Y, 5); //-Y方向延时寻迹越过两条线
  326. while (toDigital(S_FL) && toDigital(S_BL))tracking_Y(); // moveTo(0.001,0,4);
  327. //move(0, 0.01, 0); //位置调整
  328. }
  329. /*---------------------------------------*
  330. 放置函数
  331. ---------------------------------------*/
  332. void putT(int which) {
  333. //速度设置函数
  334. //延时寻迹函数
  335. //车身右侧传感器同时触发,到达预定位置
  336. //摆放角度调整
  337. //舵机运动放置物块
  338. //返回函数
  339. //寻迹返回,触发前面
  340. const double d = 0.2; //距路口距离
  341. switch (which) {
  342. case 0:
  343. {
  344. moveTo(d, 0, 2);
  345. while (toDigital(S_LF)) {
  346. moveTo( 0.001, 0, 2);
  347. }
  348. //至物料区放置并返回
  349. putSet( 0);
  350. //位置调整
  351. //返回中心区域
  352. moveTo(d, 0, 1); //是否可用升级版延时寻迹
  353. while (toDigital(S_LB)) trackingX();
  354. //位置调整
  355. }
  356. break;
  357. case 1:
  358. {
  359. putSet( 1);
  360. }
  361. break;
  362. case 2:
  363. {
  364. moveTo(d, 0, 1);
  365. while (toDigital(S_LB)) trackingX();
  366. putSet( 2);
  367. //位置调整
  368. moveTo(d, 0, 2); //是否可用升级版延时寻迹
  369. while (toDigital(S_LF)) {
  370. moveTo( 0.001, 0, 2);
  371. }
  372. //调整位置
  373. }
  374. break;
  375. }
  376. }
  377. /*---------------------------------------*
  378. 延时寻迹
  379. ---------------------------------------*/
  380. void delayTracking(int axis, double time) {
  381. unsigned long t = millis() + time* 1000 * 1.06; //参数可调
  382. if (axis == X) while (millis() < t) moveTo( 0.001, 0, 1); //trackingX();
  383. if (axis == _X) while (millis() < t)moveTo( 0.001, 0, 2) ; //tracking_X();
  384. if (axis == Y) while (millis() < t)trackingY(); //moveTo(0.001,0,3) ;//
  385. if (axis == _Y) while (millis() < t)tracking_Y(); // moveTo(0.001,0,4);//
  386. }
  387. /*---------------------------------------*
  388. 舵机动作函数
  389. ---------------------------------------*/
  390. void servoPut() { //放置函数
  391. Serial2.println( "T 8");
  392. //等待执行完毕
  393. delay( 5000);
  394. }
  395. void servoCatch() { //拿取函数
  396. Serial2.println( "T 7");
  397. //等待执行完毕
  398. delay( 4100);
  399. }
  400. void servoMiddle() { //中立待抓取
  401. Serial2.println( "T 6");
  402. //等待执行完毕
  403. delay( 2000);
  404. }
  405. /*---------------------------------------*
  406. OLED清屏函数
  407. ---------------------------------------*/
  408. void lcdClear() {
  409. u8g2.clear(); //清除屏幕所有信息
  410. }
  411. /*-------------------------------------
  412. OLED抓取任务显示函数
  413. -------------------------------------*/
  414. void GetOrderDisplay(String str) {
  415. lcdClear(); //清除屏幕信息
  416. char str1[ 4];
  417. for ( int i = 0; i < 3; i++) {
  418. str1[i] = str[i];
  419. }
  420. u8g2.drawStr( 0, 15, "Grab order:");
  421. u8g2.drawStr( 50, 35, str1); // 设置坐标,显示二维码读取信息
  422. u8g2.sendBuffer(); // 将缓存输出到屏幕
  423. delay( 200);
  424. }
  425. /*-------------------------------------*
  426. 传感器状态反馈
  427. -------------------------------------*/
  428. inline boolean toDigital(int pin) {
  429. if (analogRead(pin) >= 800) {
  430. return true;
  431. } else {
  432. return false;
  433. }
  434. }
  435. /*--------------------------------------*
  436. 前向寻迹行驶
  437. --------------------------------------*/
  438. void trackingX() {
  439. const double dx = 0.001;
  440. const double dw = 0.1;
  441. if ((!toDigital(S_FL) && !toDigital(S_FR)) || (toDigital(S_FL) && toDigital(S_FR))) {
  442. moveTo(dx, 0, 1); //+X平移
  443. }
  444. else if (!toDigital(S_FL)) { //前左传感器触发,左转
  445. moveTo( 0, dw, 5); //左偏
  446. moveTo(dx, 0, 1);
  447. }
  448. else if (!toDigital(S_FR)) { //前右传感器触发,右转
  449. moveTo( 0, dw, 6); //右偏
  450. moveTo(dx, 0, 1);
  451. }
  452. }
  453. /*--------------------------------------*
  454. 后向寻迹行驶(平移)
  455. --------------------------------------*/
  456. void tracking_X() {
  457. const double dx = 0.001;
  458. const double dw = 0.1;
  459. if ((!toDigital(S_BL) && !toDigital(S_BR)) || (toDigital(S_BL) && toDigital(S_BR))) {
  460. moveTo(dx, 0, 2); //-X平移
  461. }
  462. else if (!toDigital(S_BL)) { //后左传感器触发,右转
  463. moveTo( 0,dw, 6); //右转
  464. moveTo(dx, 0, 2);
  465. }
  466. else if (!toDigital(S_BR)) { //后右传感器触发,左转
  467. moveTo( 0,dw, 5); //左转
  468. moveTo(dx, 0, 2);
  469. }
  470. linear_v=runingSpeed;
  471. }
  472. /*--------------------------------------*
  473. 左横向寻迹行驶
  474. --------------------------------------*/
  475. void trackingY() {
  476. const double dx = 0.001;
  477. const double dw = 0.1;
  478. linear_v = 0.1;
  479. if ((!toDigital(S_LB) && !toDigital(S_LF)) || (toDigital(S_LB) && toDigital(S_LF))) {
  480. moveTo(dx, 0, 3); //+Y平移
  481. }
  482. else if (!toDigital(S_LB)) {
  483. //moveTo(0, dw, 5); //左转
  484. //moveTo(dx, 0, 3);
  485. moveTo(dx, 0, 2); //后退
  486. moveTo(dx, 0, 3);
  487. }
  488. else if (!toDigital(S_LF)) {
  489. //moveTo(0, dw, 6); //右转
  490. //moveTo(dx, 0, 3);
  491. moveTo(dx, 0, 1); //前进
  492. moveTo(dx, 0, 3);
  493. }
  494. linear_v = runingSpeed;
  495. }
  496. /*--------------------------------------*
  497. 右横向寻迹行驶(平移)
  498. --------------------------------------*/
  499. void tracking_Y() {
  500. const double dx = 0.001;
  501. const double dw = 0.1;
  502. linear_v = 0.1;
  503. if ((!toDigital(S_RB) && !toDigital(S_RF)) || (toDigital(S_RB) && toDigital(S_RF))) {
  504. moveTo(dx, 0, 4); //-Y平移
  505. }
  506. else if (!toDigital(S_RF)) {
  507. //moveTo(0, dw, 5); //左转
  508. //moveTo(dx, 0, 4); //
  509. moveTo(dx, 0, 1); //右前触发向左转
  510. moveTo(dx, 0, 4);
  511. }
  512. else if (!toDigital(S_RB)) {
  513. //moveTo(0, dw, 6); //右转
  514. //moveTo(dx, 0, 4); //
  515. moveTo(dx, 0, 2); //右后触发向右转
  516. moveTo(dx, 0, 4);
  517. }
  518. linear_v = runingSpeed;
  519. }

步进电机控制程序:


  
  1. /* 步进电机方向引脚:
  2. * dir: x: 5, y: 6, z: 7, a: 13
  3. * 步进电机步进引脚:
  4. * stp: x: 2, y: 3, z: 4, a: 12
  5. * 步进电机使能引脚(低电平有效):
  6. * en: 8
  7. * 步进电机细分设置:0, 2, 4, 8, 16
  8. * 各细分对应步进电机每周步数:
  9. * 0 --> 200
  10. * 2 --> 400
  11. * 4 --> 800
  12. * 8 --> 1600
  13. * 16 --> 3200
  14. *
  15. * 车身位置及传感器\电机接线:
  16. * Y轴
  17. * | A4 A3
  18. * | 1:X - - - - - - Y:3
  19. * | | | A2
  20. * | | | A0
  21. * | 4:Z - - - - - - A:2
  22. * |
  23. * 0-- -- -- -- -- -- -- -- X轴
  24. *
  25. *
  26. ************************************************/
  27. #include <Arduino.h>
  28. #include <AccelStepper.h> //步进电机库
  29. /*----------------------------------------------*
  30. * 步进电机端口宏定义
  31. *----------------------------------------------*/
  32. #define En_Pin 8 //步进电机使能端口
  33. #define A_Dir 13 //A电机方向引脚
  34. #define A_Step 12 //A电机步进引脚
  35. #define X_Dir 5
  36. #define X_Step 2
  37. #define Y_Dir 6
  38. #define Y_Step 3
  39. #define Z_Dir 7
  40. #define Z_Step 4
  41. /*------------------------------------------*
  42. * 步进电机参数定义
  43. *------------------------------------------*/
  44. #define L_Length 0.138 //设置a的长度 单位:m
  45. #define D_Wheel 0.0591 //车轮的直径 单位:m
  46. #define AllStep 200 //步进电机全步进一圈步数为200
  47. #define MicroStep 8 //步进电机细分数(短接帽设置)
  48. #define TotalStep 1600 //8细分下每圈步数:1600步
  49. #define ClockWise HIGH //顺时针转动
  50. #define AntiClockWise LOW //逆时针转动
  51. #define NotSendPluse false //不发送脉冲
  52. #define SendPluse true //发送脉冲
  53. #define StartUse true //开始启用
  54. #define StopUse false //停止启用步进电机
  55. /*--------------------------------------------*
  56. * 步进电机移动方向宏定义
  57. *--------------------------------------------*/
  58. #define MFord 1 //移动方向
  59. #define MBack 2
  60. #define MLeft 3
  61. #define MRight 4
  62. #define RLeft 5
  63. #define RRight 6
  64. /*--------------------------------------------*
  65. * 步进电机控制对象定义
  66. *--------------------------------------------*/
  67. AccelStepper motora(1,A_Step,A_Dir); //定义步进电机控制对象a
  68. AccelStepper motorx(1,X_Step,X_Dir);
  69. AccelStepper motory(1,Y_Step,Y_Dir);
  70. AccelStepper motorz(1,Z_Step,Z_Dir);
  71. /*---------------------------------------------*
  72. * 比率变量的设定
  73. *---------------------------------------------*/
  74. const double CarMaxSpeed= 4000; //最大步进速度
  75. const double CWheel=M_PI*D_Wheel; //车轮的周长 单位:m
  76. const double StepOfMeter=TotalStep/CWheel; //步数/米
  77. const double KMaxFre = 4000; //每秒最大步数 单位:步/秒
  78. const double angle_L= 0.323/ 90; // 将设置的小车线速度转化为整体角速度
  79. //float Linear_v = 0.3; //车速度 m/s
  80. /*-------------------------------------------*
  81. * 步进电机的初始设定方向
  82. *-------------------------------------------*/
  83. void defaultDir(){
  84. motorx.setPinsInverted(ClockWise,NotSendPluse,StartUse); //步进电机初始正转向为顺时针,是否发送步进脉冲步进,是否启用步进电机
  85. motory.setPinsInverted(ClockWise,NotSendPluse,StartUse);
  86. motorz.setPinsInverted(ClockWise,NotSendPluse,StartUse);
  87. motora.setPinsInverted(ClockWise,NotSendPluse,StartUse);
  88. }
  89. /*-------------------------------------------*
  90. * 步进电机的最大速度
  91. *-------------------------------------------*/
  92. void defaultMaxSpeed(){
  93. motorx.setMaxSpeed(CarMaxSpeed);
  94. motory.setMaxSpeed(CarMaxSpeed);
  95. motorz.setMaxSpeed(CarMaxSpeed);
  96. motora.setMaxSpeed(CarMaxSpeed);
  97. }
  98. /*-------------------------------------------*
  99. * 步进电机的初始化
  100. *-------------------------------------------*/
  101. void intiMotors(){
  102. motorx.setEnablePin(En_Pin); //设置步进电机使能端口
  103. defaultDir(); //设置步进电机初始方向
  104. defaultMaxSpeed(); //设置步进电机最大速度
  105. motorx.enableOutputs(); //步进端口使能
  106. }
  107. /*-----------------------------------------*
  108. * 步进电机运动到设定的速度
  109. *-----------------------------------------*/
  110. inline void runToSpeed(){
  111. motorx.runSpeed();
  112. motory.runSpeed();
  113. motorz.runSpeed();
  114. motora.runSpeed();
  115. }
  116. /*------------------------------------------*
  117. * 步进电机速度设置
  118. *------------------------------------------*/
  119. inline void xySetVal(double vxy,double vw,int dir){
  120. double v0=vxy*StepOfMeter; //直行速度转化为步数的速率
  121. double v1=vw*StepOfMeter; //转动的速率转化为步数的速率
  122. switch(dir){
  123. case MFord:
  124. motorx.setSpeed(-v0);
  125. motory.setSpeed(-v0);
  126. motorz.setSpeed(v0);
  127. motora.setSpeed(v0);
  128. break;
  129. case MBack:
  130. motorx.setSpeed(v0);
  131. motory.setSpeed(v0);
  132. motorz.setSpeed(-v0);
  133. motora.setSpeed(-v0);
  134. break;
  135. case MLeft:
  136. motorx.setSpeed(-v0);
  137. motory.setSpeed(v0);
  138. motorz.setSpeed(-v0);
  139. motora.setSpeed(v0);
  140. break;
  141. case MRight:
  142. motorx.setSpeed(v0);
  143. motory.setSpeed(-v0);
  144. motorz.setSpeed(v0);
  145. motora.setSpeed(-v0);
  146. break;
  147. case RLeft:
  148. motorx.setSpeed(v1);
  149. motory.setSpeed(v1);
  150. motorz.setSpeed(v1);
  151. motora.setSpeed(v1);
  152. break;
  153. case RRight:
  154. motorx.setSpeed(-v1);
  155. motory.setSpeed(-v1);
  156. motorz.setSpeed(-v1);
  157. motora.setSpeed(-v1);
  158. break;
  159. default: break;
  160. }
  161. }
  162. /*-----------------------------------------*
  163. * 步进电机移动固定距离
  164. *----------------------------------------*/
  165. void moveTo(double dxy,double dw,int dir){
  166. if((dxy == 0) && (dw == 0)) return;
  167. double t1 = dxy/ linear_v;
  168. dw=angle_L*dw; //将角度运算转化为长度运行
  169. double t2 =dw/linear_v;
  170. double t_last=max(t1,t2);
  171. if(t_last== 0) return; //防止发生不可预料的错误
  172. //xySetVal(dxy/t,dw/t,dir);
  173. xySetVal(linear_v,linear_v,dir);
  174. //XYStar();
  175. unsigned long delta_t=millis()+t_last* 1000* 1.03;
  176. while(millis()< delta_t){
  177. runToSpeed();
  178. }
  179. stopHalSec();
  180. }
  181. /*---------------------------------------------*
  182. * 步进电机使能开关
  183. *---------------------------------------------*/
  184. inline void xyStop(){xySetVal( 0, 0, 0); runToSpeed(); motorx.disableOutputs();} //步进电机使能关闭
  185. inline void xyStar(){motorx.enableOutputs();} //步进电机使能开启
  186. /*---------------------------------------------*
  187. * 暂停(速度为零)
  188. *---------------------------------------------*/
  189. void stopHalSec(){
  190. xySetVal( 0, 0, 0);
  191. runToSpeed();
  192. }

二维码和颜色识别库头文件:


  
  1. /*
  2. *
  3. */
  4. #ifndef SCANNER_H
  5. #define SCANNER_H
  6. #include <Arduino.h>
  7. #define MAX_SCANNERS 2
  8. typedef struct{
  9. uint8_t type;
  10. String value;
  11. } scanner_t;
  12. class Scanner{
  13. private:
  14. uint8_t scannerIndex;
  15. uint8_t _interface;
  16. uint8_t _qr_scanner_time;
  17. String _qr;
  18. String _color;
  19. typedef enum{
  20. QRCODE = 0,
  21. COLOR = 1
  22. }ScannerInterfaceType;
  23. String serialRead();
  24. bool receiveCmd();
  25. String readQRCode(unsigned long * _t);
  26. String readColor();
  27. public:
  28. Scanner();
  29. ~Scanner();
  30. void setType(uint8_t interface);
  31. void scan();
  32. String getData();
  33. };
  34. #endif

二维码识别和颜色读取库函数:


  
  1. /*
  2. * Serial -> information print
  3. * Serial2 -> qrCode
  4. * color_sensor_pin_define:
  5. * s0 -> 30
  6. * s1 -> 31
  7. * s2 -> 34
  8. * s3 -> 35
  9. * out -> 33
  10. * led -> 32
  11. * vcc -> 5V
  12. * gnd -> gnd
  13. */
  14. #include "scanner.h"
  15. //二维码模块触发检测
  16. unsigned char hexdata[ 9] = { 0x7E, 0x00, 0x08, 0x01, 0x00, 0x02, 0x01, 0xAB, 0xCD};
  17. //颜色扫描端口设置
  18. uint8_t s0 = 30;
  19. uint8_t s1 = 31;
  20. uint8_t s2 = 34;
  21. uint8_t s3 = 35;
  22. uint8_t out = 33;
  23. uint8_t led = 32;
  24. static scanner_t scanners[MAX_SCANNERS];
  25. uint8_t scannerCount = 0; //扫描对象计数
  26. //开始检测二维码返回数据
  27. static void readHeader(){
  28. while(Serial1.read() != 0x31) delay( 10);
  29. }
  30. //颜色扫描端口初始化
  31. static void initTcs(){
  32. pinMode(s0, OUTPUT);
  33. pinMode(s1, OUTPUT);
  34. pinMode(s2, OUTPUT);
  35. pinMode(s3, OUTPUT);
  36. pinMode(out, INPUT);
  37. pinMode(led, OUTPUT);
  38. /*S0和S1的设置可以缩放输出频率
  39. S0:L,S1:L---Powerdown
  40. S0:L,S1:H---2%
  41. S0:H,S1:L---20%
  42. S0:H,S1:H---100%
  43. */
  44. //拓展频率设置为20%
  45. digitalWrite(s0, HIGH);
  46. digitalWrite(s1, LOW);
  47. }
  48. //二维码扫描开启
  49. String Scanner::readQRCode(unsigned long * _t){
  50. String incomingStr = "";
  51. while( true){
  52. incomingStr = Serial1.readStringUntil( '\r');
  53. if((incomingStr.length() >= 3) || (millis() - * _t > _qr_scanner_time))
  54. break;
  55. }
  56. return incomingStr;
  57. }
  58. //读取颜色
  59. String Scanner::readColor(){
  60. int rcount= 0,gcount= 0,bcount= 0; //三色计数器
  61. float R_COE = 0.29, G_COE = 0.27, B_COE = 0.31; //白平衡系数
  62. float rr = 0, gg = 0, bb = 0;
  63. //识别10次取最大的一个颜色
  64. digitalWrite(led, HIGH);
  65. for( int i= 0;i< 100;i++){
  66. int r = 0, g = 0, b = 0; //脉冲计数器
  67. digitalWrite(s2, LOW);
  68. digitalWrite(s3, LOW);
  69. //count OUT, RED
  70. r = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH); //检测红色脉冲时长
  71. digitalWrite(s3, HIGH);
  72. //count OUT, BLUE
  73. b = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH); //检测蓝色脉冲时长
  74. digitalWrite(s2, HIGH);
  75. //count OUT, GREEN
  76. g = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH); //检测绿色脉冲时长
  77. //颜色白平衡
  78. rr = r * R_COE;
  79. gg = g * G_COE;
  80. bb = b * B_COE;
  81. if(rr < bb && rr < gg){
  82. rcount++; //红色最小就是红色
  83. }
  84. else if(bb < rr && bb < gg){
  85. bcount++; //蓝色最小就是蓝色
  86. }
  87. else if(gg < rr && gg < bb){
  88. gcount++; //绿色最小就是绿色
  89. } else{
  90. //
  91. }
  92. delay( 10);
  93. }
  94. digitalWrite(led, LOW); //关灯
  95. if((rcount>bcount)&&(rcount>gcount)){
  96. return "1";
  97. } else if((gcount>rcount)&&(gcount>bcount)){
  98. return "2";
  99. } else if((bcount>rcount)&&(bcount>gcount)){
  100. return "3";
  101. }
  102. }
  103. Scanner::Scanner(){
  104. _qr_scanner_time = 5000; // 5s,二维码扫描5秒钟
  105. if(scannerCount < MAX_SCANNERS){
  106. this->scannerIndex = scannerCount++;
  107. }
  108. else
  109. return;
  110. }
  111. //析购函数
  112. Scanner::~Scanner(){
  113. }
  114. void Scanner::setType(uint8_t interface){
  115. _interface = interface;
  116. scanners[ this->scannerIndex].type = _interface;
  117. if(_interface == COLOR)
  118. initTcs(); //端口初始化
  119. }
  120. String Scanner::serialRead(){
  121. if(_interface == QRCODE){
  122. unsigned long wait_t = millis();
  123. return readQRCode(& wait_t);
  124. } else if(_interface == COLOR){
  125. return readColor();
  126. }
  127. }
  128. bool Scanner::receiveCmd(){
  129. String data = serialRead();
  130. if(data.length() > 0){
  131. if(_interface == QRCODE){
  132. _qr = data;
  133. scanners[ this->scannerIndex].value = _qr;
  134. } else if(_interface == COLOR){
  135. if(_color.indexOf(data) < 0){ //若字符串_color中没有该字符data则系统返回-1
  136. _color += data;
  137. if(_color.length() >= 2){ //c++中,length()只是用来获取字符串的长度。 例如:string str = “asdfghjkl”,则,str.length() = 9。
  138. if(_color.equals( "23") || _color.equals( "32"))
  139. _color += "1";
  140. else if(_color.equals( "13") || _color.equals( "31"))
  141. _color += "2";
  142. else if(_color.equals( "12") || _color.equals( "21"))
  143. _color += "3";
  144. scanners[ this->scannerIndex].value = _color;
  145. }
  146. }
  147. else{
  148. return false;
  149. }
  150. }
  151. return true;
  152. } else{
  153. return false;
  154. }
  155. }
  156. void Scanner::scan(){
  157. switch(_interface){
  158. case QRCODE: Serial1.write(hexdata, 9); readHeader(); break;
  159. case COLOR: /****/ ; break;
  160. }
  161. if(receiveCmd()){
  162. return;
  163. }
  164. else if(_interface == QRCODE){
  165. scan();
  166. }
  167. }
  168. String Scanner::getData(){
  169. return scanners[ this->scannerIndex].value;
  170. }

 

 

白平衡系数计算:

(为了降低环境对颜色传感器的影响,在颜色识别的库函数中有一组白平衡系数要提前检测输入进去)


  
  1. //颜色扫描端口设置
  2. uint8_t s0 = 30;
  3. uint8_t s1 = 31;
  4. uint8_t s2 = 34;
  5. uint8_t s3 = 35;
  6. uint8_t out = 33;
  7. uint8_t led = 32;
  8. void setup(){
  9. Serial.begin( 9600);
  10. pinMode(s0, OUTPUT);
  11. pinMode(s1, OUTPUT);
  12. pinMode(s2, OUTPUT);
  13. pinMode(s3, OUTPUT);
  14. pinMode(out, INPUT);
  15. pinMode(led, OUTPUT);
  16. /*S0和S1的设置可以缩放输出频率
  17. S0:L,S1:L---Powerdown
  18. S0:L,S1:H---2%
  19. S0:H,S1:L---20%
  20. S0:H,S1:H---100%
  21. */
  22. digitalWrite(s0, HIGH);
  23. digitalWrite(s1, HIGH);
  24. //白平衡计算,10组算平均值
  25. hanshu();
  26. }
  27. void hanshu(){
  28. int r = 0, g = 0, b = 0; //脉冲计数器
  29. float R_COE[ 10],G_COE[ 10], B_COE[ 10]; //白平衡系数
  30. digitalWrite(led, HIGH); //开灯
  31. delay( 150);
  32. for( int i= 0;i< 10;i++){
  33. digitalWrite(s2, LOW);
  34. digitalWrite(s3, LOW);
  35. //count OUT, RED
  36. r = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH); //检测红色脉冲时长
  37. digitalWrite(s3, HIGH);
  38. //count OUT, BLUE
  39. b = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH); //检测蓝色脉冲时长
  40. digitalWrite(s2, HIGH);
  41. //count OUT, GREEN
  42. g = pulseIn(out, digitalRead(out) == HIGH ? LOW : HIGH); //检测绿色脉冲时长
  43. R_COE[i]=r/ 255; //红色白平衡系数
  44. Serial.print( "R_COE:");
  45. Serial.println(R_COE[i]);
  46. G_COE[i]=g/ 255; //绿色白平衡系数
  47. Serial.print( "G_COE:");
  48. Serial.println(G_COE[i]);
  49. B_COE[i]=b/ 255; //蓝色白平衡系数
  50. Serial.print( "B_COE:");
  51. Serial.println(B_COE[i]);
  52. }
  53. float rr,gg,bb;
  54. for( int i= 0;i< 10;i++){
  55. rr+=R_COE[i];
  56. gg+=G_COE[i];
  57. bb+=B_COE[i];
  58. }
  59. //输出白平衡平均参数
  60. Serial.print( "R_balance:");
  61. Serial.println(rr);
  62. Serial.print( "G_balance:");
  63. Serial.println(gg);
  64. Serial.print( "B_balance:");
  65. Serial.println(bb);
  66. }
  67. void loop(){
  68. }

==============================================================

更新(2019.10.12)

        直接看代码是一件痛苦的事情,可能用语言或者图来描述一下算法才是合理的,或者说才是思想的体现,因为代码里面充满了细节,而这些细节只有写代码的才知道为了什么,而有用的是整个思路。

                                                  

 主控制板程序:

                                                  

       负责控制和处理  颜色传感器,步进电机,二维码模块;主控制板的程序就是上图的四个,因为我写的时候使用VS编辑器写的,所以里面有很多多余的东西,我重新整理了下。

         BigBigDiao_2:这个是主程序,但是里面也有一些其他的函数。

         Stepper:这部分是步进电机的功能函数,步进电机不太懂的可以看看太极创客的视频和资料,讲的非常好 (http://www.taichi-maker.com/homepage/reference-index/circuit-reference-index/)。

         剩下的两个是关于颜色识别和二维识别的功能函数。

         这个文件夹的程序是烧录在主控制板上的。

 

 

控制板程序:

        负责控制舵机,也就是机械臂部分的,应为用一个控制板会出现冲突,所以才搞了两块,主控制板与副控制板通信实现舵机控制,从而实现机械臂的抓取放置动作。

                  

       这部分程序只有一个文件,但是这个要提前安装一个库,就是下图的库。

                                            -

       这部分程序烧录在副控制板。

  

程序思路(已经有一段时间了,有些东西也忘了,主要看思路):

        通过黑标计数黑线来实现位置的大致判断。首先从出发区出发,在到达第一物块和第二个物块的位置时,用颜色传感器识别这两个位置物料的颜色,第三个位置自动判断。到达二维码区开启二维码模块扫描功能,获得抓放次序,然后返回物料区的中心位置(这是理解自动规划路径的关键点,其实就是两个for循环比较实现的),还有就是放置区的颜色位置是死的,提前输入到宏定义里面就好了。每次抓取都从中心位置出发,然后回到出发位置。放置也是从中心位置出发,然后回到中心位置。(有更高级的思路,这里只是解释自己程序的思路)。最后回到出发区。

       黑标和颜色识别在某些环境下会出现较大偏差,这是可以改进的地方。

       还有一个白平衡系数,之前写了我就不赘述了。

     

 

 


转载:https://blog.csdn.net/C1664510416/article/details/89402154
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场