【S131】智能物料搬运机器人
作品说明 |
作者:卢明戈 刘欣
单位:武汉科技大学
指导老师:曾飞 王涛
1. 市场调研及市场前景说明
智能搬运机器人以电动机作为驱动系统,运用单片机、传感器等技术达到其智能移动的目的,实现行走、路径规划、二维码扫描、机械手抓取、颜色以及形状识别等多种功能动作的操作,因此它是一种典型的机电一体化产品,在现代生产中应用日益广泛,作用越来越重要。机器人技术是综合了计算机、控制、机构学、传感技术等多学科而形成的高新技术,是当代研究十分活跃,应用日益广泛的领域,现在国际上对机器人的概念已经逐渐趋近一致。一般来说,人们都可以接受这种说法,即机器人是靠自身动力和控制能力来实现各种功能的一种机器。联合国标准化组织采纳了美国机器人协会给机器人下的定义:“一种可编程和多功能的,用来搬运材料、零件、工具的操作机;或是为了执行不同的任务而具有可改变和可编编程动作的专门系统”。
本项目研究的内容是智能小车,又称轮式机器人,可以在人类无法适应的恶劣和危险环境中代替人工作,它是一个集环境感知、规划决策、自动驾驶等功能于一体的智能系统,现如今已在诸多领域有广泛的应用,对于我们接触智能机器人方面知识较少的大学生来说,的确是一个与时俱进、富有意义又极具挑战的设计课题。
作品说明
智能物料搬运机器人
2. 智能物料搬运机器人总体设计思路
2.1 系统设计阶段
① 根据智能物料搬运机器人所要实现的目标,明确所采用的机器人的目的和任务。
② 分析机器人所在系统的工作环境。
③ 根据智能物料搬运机器人的工作要求和工作环境,基本确定机器人的功能和方案。例如场地目标位置识别、自主路径规划、自主移动、二维码读取、物料颜色识别或形状识别、物料抓取和搬运等功能。
2.2 技术设计阶段
① 根据系统的要求来确定机器人的允许的空间工作范围,选择机器人的坐标系形式和工作方式。
② 拟定机器人的运动路线和空间作业图。
③ 确定驱动系统的类型。
④ 选择各部件的具体结构以及尺寸,进行机器人总装图的设计与装配。
⑤ 绘制机器人的零件图,并确定尺寸。
3. 智能物料搬运机器人系统以及功能介绍
3.1 运动系统
由四个DC3V-6V的直流减速电机组成,四台设备装备在智能物料搬运机器人的底层,由两个TB6612FNG电机驱动板模块控制,实现机器人的四轮同时前进、后退,以及原地的转向。DC3V-6V的工作电压在3v-6v,TB6612FNG的工作电压为5v,与机器人总体设计规定的12v有差异,需要降压模块进行电压的转化,以达到电机与驱动模块的正常工作以及与控制芯片arduino的交互控制。
3.2 控制系统
arduino构建于开放原始码simple I/O介面版,并且具有使用类似Java、C语言的Processing/Wiring开发环境。主要包含两个主要的部分:硬件部分是可以用来做电路连接的Arduino电路板;另外一个则是Arduino IDE,你的计算机中的程序开发环境。你只要在IDE中编写程序代码,将程序上传到Arduino电路板后,程序便会告诉Arduino电路板要做些什么了,与传统的控制控制芯片相比arduino的优势十分明显:
① 使用Arduino做项目,几乎不用考虑硬件部分的设计,可以按需求选用Arduino的控制板、扩展板等组成自己的需要的硬件系统。
② 学习Arduino 单片机可以完全不需要了解其内部硬件结构和寄存器设置,仅仅知道它的端口作用即可;可以不懂硬件知识,只要会简单的C语言,就可用Arduino 单片机编写程序。使用单片机则需要了解单片机内部硬件结构和寄存器的设置,使用汇编语言或者C语言编写底层硬件函数。
③ Arduino 软件语言仅仅需掌握少数几个指令,而且指令的可读性也强,稍微懂一点C语言即可,轻松上手,快速应用。
④ Arduino 的理念就是开源,软硬件完全开放,技术上不做任何保留。针对周边I/O设备的Arduino 编程,很多常用的I/O 设备都已经带有库文件或者样例程序,在此基础上进行简单的修改,即可编写出比较复杂的程序,完成功能多样化的作品。而单片机的软件开发,需要软件工程师编写底层到应用层的程序。没有那么多现成的库函数可以使用。
⑤ Arduino 由于开源,也就意味着从Arduino 相关网站、博客,论坛里得到大量的共享资源,在共享资讯的辅助下,通过资源整合,能够加快您创作作品的速度及效率。
⑥ 相对其他开发板,Arduino 及周边产品相对质廉价优,学习或创作成本低,重要一点是:烧录代码不需要烧录器,直接用USB线就可以完成下载。
并且Arduino能通过各种各样的传感器来感知环境,通过控制机械臂、马达、显示器和其他的装置来反馈、影响环境。板子上的微控制器可以通过Arduino的编程语言来编写程序,编译成二进制文件,烧录进微控制器。对Arduino的编程是通过 Arduino编程语言 (基于 Wiring)和Arduino开发环境(基于 Processing)来实现的。基于Arduino的项目,可以只包含Arduino,也可以包含Arduino和其他一些在PC上运行的软件,他们之间进行通信 (比如 Flash, Processing, MaxMSP)来实现。因为以上特性选用arduino作为智能物料搬运机器人的控制器是十分合适的。
4. 识别及显示系统
4.1 颜色传感器
(1)模块描述
颜色传感器是一种传感装置,是将物体颜色同前面已经示教过的参考颜色进行比较来检测颜色的装置。当两个颜色在一定的误差范围内相吻合时,输出检测结果。一个新型传感器能敏锐的察觉到颜色变化有助于一线工人正确的分辨出会所,颜色等问题。颜色传感器一直用装配线来检测特定的组件。颜色传感器的挑战是检测微妙差异相似或高度反光的颜色。例如,金属涂料在汽车工业中使用很难区分灰度的颜色或黄金。匹配组件这是重要的,如镜子的身体或保险杠都离不开传感器协助。此外,颜色传感器通过数量有限的颜色可以检测,并通过他们有限的能力迅速改变设置或处理多个颜色。一个典型的颜色传感器具有高强度白光LED,光在目标项目调制。反射从目标是分析的成分红,绿,蓝(RGB)值和强度。此信息用于验证正确的部分和组装,准确控制制成品的颜色。
(2)模块参数说明
① 板载TCS3200颜色传感器
② 支持3V-5V电压输入
③ 芯片的引脚全部已经引出,插针标准100mil(2.54mm),方便用于点阵板
④ PCB尺寸:31.6(mm)*24.4(mm)
(3)模块接口说明
Pin 6 <-----> S0
Pin 5 <-----> S1
Pin 4 <-----> S2
Pin 3 <-----> S3
Pin 2 <-----> OUT
5V <-----> VCC
GND <-----> GND
(4)代码
#include <TimerOne.h> //申明库文件 //把TCS3200颜色传感器各控制引脚连到Arduino数字端口 #define S0 6 //物体表面的反射光越强,TCS3002D内置振荡器产生的方波频率越高, #define S1 5 //S0和S1的组合决定输出信号频率比例因子,比例因子为2% //比率因子为TCS3200传感器OUT引脚输出信号频率与其内置振荡器频率之比 #define S2 4 //S2和S3的组合决定让红、绿、蓝,哪种光线通过滤波器 #define S3 3 #define OUT 2 //TCS3200颜色传感器输出信号连接到Arduino中断0引脚,并引发脉冲信号中断 //在中断函数中记录TCS3200输出信号的脉冲个数 #define LED 7 //控制TCS3200颜色传感器是否点亮LED灯 float g_SF[3]; //从TCS3200输出信号的脉冲数转换为RGB标准值的RGB比例因子 int g_count = 0; // 计算与反射光强相对应TCS3200颜色传感器输出信号的脉冲数 // 数组用于存储在1s内TCS3200输出信号的脉冲数,它乘以RGB比例因子就是RGB标准值 int g_array[3]; int g_flag = 0; // 滤波器模式选择顺序标志 // 初始化TSC3200各控制引脚的输入输出模式 //设置TCS3002D的内置振荡器方波频率与其输出信号频率的比例因子为2% void TSC_Init() { pinMode(S0, OUTPUT); pinMode(S1, OUTPUT); pinMode(S2, OUTPUT); pinMode(S3, OUTPUT); pinMode(OUT, INPUT); pinMode(LED, OUTPUT); digitalWrite(S0, LOW); digitalWrite(S1, HIGH); } //选择滤波器模式,决定让红、绿、蓝,哪种光线通过滤波器 void TSC_FilterColor(int Level01, int Level02) { if(Level01 != 0) Level01 = HIGH; if(Level02 != 0) Level02 = HIGH; digitalWrite(S2, Level01); digitalWrite(S3, Level02); } //中断函数,计算TCS3200输出信号的脉冲数 void TSC_Count() { g_count ++ ; } //定时器中断函数,每1s中断后,把该时间内的红、绿、蓝三种光线通过滤波器时, //TCS3200输出信号脉冲个数分别存储到数组g_array[3]的相应元素变量中 void TSC_Callback() { switch(g_flag) { case 0: Serial.println("->WB Start"); TSC_WB(LOW, LOW); //选择让红色光线通过滤波器的模式 break; case 1: Serial.print("->Frequency R="); Serial.println(g_count); //打印1s内的红光通过滤波器时,TCS3200输出的脉冲个数 g_array[0] = g_count; //存储1s内的红光通过滤波器时,TCS3200输出的脉冲个数 TSC_WB(HIGH, HIGH); //选择让绿色光线通过滤波器的模式 break; case 2: Serial.print("->Frequency G="); Serial.println(g_count); //打印1s内的绿光通过滤波器时,TCS3200输出的脉冲个数 g_array[1] = g_count; //存储1s内的绿光通过滤波器时,TCS3200输出的脉冲个数 TSC_WB(LOW, HIGH); //选择让蓝色光线通过滤波器的模式 break; case 3: Serial.print("->Frequency B="); Serial.println(g_count); //打印1s内的蓝光通过滤波器时,TCS3200输出的脉冲个数 Serial.println("->WB End"); g_array[2] = g_count; //存储1s内的蓝光通过滤波器时,TCS3200输出的脉冲个数 TSC_WB(HIGH, LOW); //选择无滤波器的模式 break; default: g_count = 0; //计数值清零 break; } } //设置反射光中红、绿、蓝三色光分别通过滤波器时如何处理数据的标志 //该函数被TSC_Callback( )调用 void TSC_WB(int Level0, int Level1) { g_count = 0; //计数值清零 g_flag ++; //输出信号计数标志 TSC_FilterColor(Level0, Level1); //滤波器模式 Timer1.setPeriod(1000000); //设置输出信号脉冲计数时长1s } //初始化 void setup() { TSC_Init(); Serial.begin(9600); //启动串行通信 Timer1.initialize(); // defaulte is 1s Timer1.attachInterrupt(TSC_Callback); //设置定时器1的中断,中断调用函数为TSC_Callback() //设置TCS3200输出信号的上跳沿触发中断,中断调用函数为TSC_Count() attachInterrupt(0, TSC_Count, RISING); digitalWrite(LED, HIGH);//点亮LED灯 delay(4000); //延时4s,以等待被测物体红、绿、蓝三色在1s内的TCS3200输出信号脉冲计数 //通过白平衡测试,计算得到白色物体RGB值255与1s内三色光脉冲数的RGB比例因子 g_SF[0] = 255.0/ g_array[0]; //红色光比例因子 g_SF[1] = 255.0/ g_array[1] ; //绿色光比例因子 g_SF[2] = 255.0/ g_array[2] ; //蓝色光比例因子 //打印白平衡后的红、绿、蓝三色的RGB比例因子 Serial.println(g_SF[0],5); Serial.println(g_SF[1],5); Serial.println(g_SF[2],5); //红、绿、蓝三色光分别对应的1s内TCS3200输出脉冲数乘以相应的比例因子就是RGB标准值 //打印被测物体的RGB值 for(int i=0; i<3; i++) Serial.println(int(g_array[i] * g_SF[i])); } //主程序 void loop() { g_flag = 0; //每获得一次被测物体RGB颜色值需时4s delay(4000); //打印出被测物体RGB颜色值 for(int i=0; i<3; i++) Serial.println(int(g_array[i] * g_SF[i])); } |
颜色传感器
arduino与传感器的连接
原理图
4.2显示屏模块
(1)模块描述
本模块的显示区域是128*64的点阵,每个点都能自己发光,所以它没有背光这一说法!可显示汉字、ASC11、图案等,看上去非常漂亮、对比度非常高!
(2)模块参数说明
① 无需背光,能自行发光
② 分辨率高:128*64
③ 可视角度大:>160度
④ 支持众多控制芯片:全面兼容Arduino等等
⑤ 宽电压支持:支持3-5V直流
⑥ 工作温度:-40度-70度
⑦ 模块体积(长宽厚):27.3mm*27.8mm*3.7mm
⑧ IO口占用少:采用SPI或IIC通信方式,最多只要4个IO口就能驱动
⑨ 驱动芯片:SSD1306
(3)模块接口说明
VCC——> +5V GND——> GND NC ——> 悬空 DIN ——> 9 CLK——> 10 CS ——> 12
D/C ——> 11 RES——> 13
(4)代码
#define OLED_DC 11 #define OLED_CS 12 #define OLED_CLK 10 #define OLED_MOSI 9 #define OLED_RESET 13 #include "SSD1306.h" SSD1306 oled(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); #define NUMFLAKES 10 #define XPOS 0 #define YPOS 1 #define DELTAY 2 #define LOGO16_GLCD_HEIGHT 16 #define LOGO16_GLCD_WIDTH 16 static const unsigned char __attribute__ ((progmem)) logo16_glcd_bmp[]={ 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0xf8, 0xbe, 0x9f, 0xff, 0xf8, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x20, 0x3c, 0x3f, 0x3f, 0x1f, 0x19, 0x1f, 0x7b, 0xfb, 0xfe, 0xfe, 0x07, 0x07, 0x07, 0x03, 0x00, }; void setup() { Serial.begin(9600); // If you want to provide external 7-9V VCC, uncomment next line and comment the one after //oled.ssd1306_init(SSD1306_EXTERNALVCC); // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) oled.ssd1306_init(SSD1306_SWITCHCAPVCC); // init done oled.display(); // show splashscreen delay(2000); oled.clear(); // clears the screen and buffer // Fill screen oled.fillrect(0, 0, SSD1306_LCDWIDTH-1, SSD1306_LCDHEIGHT-1, WHITE); oled.display(); delay(2000); // draw a single pixel oled.setpixel(10, 10, WHITE); oled.display(); delay(2000); oled.clear(); // draw many lines testdrawline(); oled.display(); delay(2000); oled.clear(); // draw rectangles testdrawrect(); oled.display(); delay(2000); oled.clear(); // draw multiple rectangles testfillrect(); oled.display(); delay(2000); oled.clear(); // draw mulitple circles testdrawcircle(); oled.display(); delay(2000); oled.clear(); // draw a white circle, 10 pixel radius, at location (32,32) oled.fillcircle(32, 32, 10, WHITE); oled.display(); delay(2000); oled.clear(); // draw the first ~12 characters in the font testdrawchar(); oled.display(); delay(2000); oled.clear(); // draw a string at location (0,0) oled.drawstring(0, 0, "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation"); oled.display(); delay(2000); oled.clear(); // miniature bitmap display oled.drawbitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); oled.display(); // invert the display oled.ssd1306_command(SSD1306_INVERTDISPLAY); delay(1000); oled.ssd1306_command(SSD1306_NORMALDISPLAY); delay(1000); // draw a bitmap icon and 'animate' movement testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); } void loop() { for (uint8_t i=0; i<SSD1306_LCDWIDTH; i++) { for (uint8_t j=0; j<SSD1306_LCDHEIGHT; j++) { oled.setpixel(i, j, WHITE); oled.display(); } } } void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { uint8_t icons[NUMFLAKES][3]; srandom(666); // whatever seed // initialize for (uint8_t f=0; f< NUMFLAKES; f++) { icons[f][XPOS] = random() % SSD1306_LCDWIDTH; icons[f][YPOS] = 0; icons[f][DELTAY] = random() % 5 + 1; Serial.print("x: "); Serial.print(icons[f][XPOS], DEC); Serial.print(" y: "); Serial.print(icons[f][YPOS], DEC); Serial.print(" dy: "); Serial.println(icons[f][DELTAY], DEC); } while (1) { // draw each icon for (uint8_t f=0; f< NUMFLAKES; f++) { oled.drawbitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); } oled.display(); delay(200); // then erase it + move it for (uint8_t f=0; f< NUMFLAKES; f++) { oled.drawbitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); // move it icons[f][YPOS] += icons[f][DELTAY]; // if its gone, reinit if (icons[f][YPOS] > SSD1306_LCDHEIGHT) { icons[f][XPOS] = random() % SSD1306_LCDWIDTH; icons[f][YPOS] = 0; icons[f][DELTAY] = random() % 5 + 1; } } } } void testdrawchar(void) { for (uint8_t i=0; i < 168; i++) { oled.drawchar((i % 21) * 6, i/21, i); } } void testdrawcircle(void) { for (uint8_t i=0; i<SSD1306_LCDHEIGHT; i+=2) { oled.drawcircle(63, 31, i, WHITE); } } void testdrawrect(void) { for (uint8_t i=0; i<SSD1306_LCDHEIGHT; i+=2) { oled.drawrect(i, i, SSD1306_LCDWIDTH-i, SSD1306_LCDHEIGHT-i, WHITE); } } void testfillrect(void) { for (uint8_t i=0; i<SSD1306_LCDHEIGHT; i++) { // alternate colors for moire effect oled.fillrect(i, i, SSD1306_LCDWIDTH-i, SSD1306_LCDHEIGHT-i, i%2); } } void testdrawline() { for (uint8_t i=0; i<SSD1306_LCDWIDTH; i+=4) { oled.drawline(0, 0, i, SSD1306_LCDHEIGHT-1, WHITE); oled.display(); } for (uint8_t i=0; i<SSD1306_LCDHEIGHT; i+=4) { oled.drawline(0, 0, SSD1306_LCDWIDTH-1, i, WHITE); oled.display(); } delay(1000); for (uint8_t i=0; i<SSD1306_LCDWIDTH; i+=4) { oled.drawline(i, SSD1306_LCDHEIGHT-1, 0, 0, BLACK); oled.display(); } for (uint8_t i=0; i<SSD1306_LCDHEIGHT; i+=4) { oled.drawline(SSD1306_LCDWIDTH - 1, i, 0, 0, BLACK); oled.display(); } } |
显示屏模块
模块与arduino的连接
4.3二维码模块
(1)模块描述
首先,输入端输入图像,通过识别器识别,输出成0、1的二进制数,然后将信号转换成指令。
(2)模块参数说明
1) 光学系统: CMOS
2) 捕捉光源: 617nm LED
3) 照明光源: 6500K LED
4) 识读角度 :旋转 360 °
5) 偏转± 60 °
6) 倾斜± 65°
7) 扫描角度: 34 °(水平) 26°(垂直)
8) 最低对比度:30%
9) 分辨率:≥ 0. 1mm(4mil)
10) 电压: DC 5V
11) 电流:扫描时 120mA / 待机时30mA
12) 接口: USB,URAT
13) 工作温度: 温度: 0℃~50 ℃
14) 存储温度: -40 ℃~70 ℃
15) 工作湿度:10%~80%
16) 环境光: 环境光: 0~86,000 lux
二维码模块
5. 定位系统
首先,定位系统需要多个传感器与arduino板连接后进行综合使用。小车以循迹为主,以红外传感器辅助定位。
红外避障传感器模块
(1)模块描述
该传感器模块对环境光线适应能力强,其具有一对红外线发射与接收管,发射管发射出一定频率的红外线,当检测方向遇到障碍物(反射面)时,红外线反射回来被接 收管接收,经过比较器电路处理之后,绿色指示灯会亮起,同时信号输出接口输出数字信号(一个低电平信号),可通过电位器旋钮调节检测距离,有效距离范围 2~30cm,工作电压为3.3V-5V。该传感器的探测距离可以通过电位器调节、具有干扰小、便于装配、使用方便等特点,可以广泛应用于机器人避障、避障小车、流水线计数及黑白线循迹等众多场合。
(2)模块参数说明
① 当模块检测到前方障碍物信号时,电路板上绿色指示灯点亮电平,同时OUT端口持续输出低电平信号,该模块检测距离2~30cm,检测角度35°,检测距离可以通过电位器进行调节,顺时针调电位器,检测距离增加;逆时针调电位器,检测距离减少。
② 传感器主动红外线反射探测,因此目标的反射率和形状是探测距离的关键。其中黑色探测距离最小,白色最大;小面积物体距离小,大面积距离大。
③ 传感器模块输出端口OUT可直接与单片机IO口连接即可,也可以直接驱动一个5V继电器。连接方式:VCC-VCC;GND-GND;OUT-IO
④ 比较器采用LM393,工作稳定
⑤ 可采用3-5V直流电源对模块进行供电。当电源接通时,红色电源指示灯点亮
⑥ 具有3mm的螺丝孔,便于固定、安装
⑦ 电路板尺寸:3.2CM*1.4CM
(3)模块接口说明
① VCC连接: Arduino 5V(说明书上写3.3V-5V,我的硬件只在5V下正常工作)
② GND连接: Arduino GND
③ OUT连接: Digital 13
(4)代码
int PIN_SENSOR = 13; void setup() { pinMode(PIN_SENSOR, INPUT); Serial.begin(9600); } void loop() { int x = digitalRead(PIN_SENSOR); Serial.println(x); } |
红外模块
电路图
Arduino与红外模块的连接
6. 抓取系统
6.1 升降装置
通过升降装置(图一)来控制手爪(图二)的高度。
图一
图二
通过第二层底盘上的舵机(图三)来控制皮带的传动,从而控制手爪抓取部分的升降(图四)。
图三
图四
6.2 抓取装置
6.2.1 舵机模块
① 说明
舵机的旋转不像普通电机那样只是转圈圈,它可以根据你的指令旋转到0至180度之间的任意角度然后精准的停下来,常用于控制机器人。舵机的转动的角度是通过调节PWM(脉冲宽度调制)信号的占空比来实现的。需要使用Arduino上的PWM口控制(数字前带~的),Arduino 的驱动能力有限,所以当需要控制1 个以上的舵机时需要外接电源。一个机器人经常需要很多个舵机同时工作,此时需要加一个舵机控制板,舵机控制板本身是一个单片机,它不但能接16/24/32个舵机,同时也简化了舵机操作命令。小车使用的是9g的小舵机,用arduino板上的5V供电,大的舵机有的需要外部供电才能驱动,外接电源时需要将降到舵机指定的电压,否则会烧坏舵机。
② 接线
GND(棕色)接 Arduino GND
PWM(橙色)接 Arduino Digital 10
VCC(红色)接 Arduino 5V
③ 代码
#include <Servo.h> #define PIN_SERVO 10 Servo myservo; void setup() { myservo.attach(PIN_SERVO); } void loop() { myservo.write(0); delay(1000); myservo.write(80); delay(1000); myservo.write(160); delay(1000); myservo.write(80); delay(1000); myservo.write(0); delay(1000); } |
舵机模块
6.2.2 手爪
通过舵机控制手爪抓取实物。
图一
图二
抓取物体
7. 制作过程
8. 项目总结
在智能小车的设计初期,本项目遇到了许多方面的困难,比如小车尺寸的确定、零件的选择、绘制三维图的过程等。在为期一个月的时间中大家坚持下来克服种种困难,完成了智能小车的设计雏形,在此过程中大家学会了在做任何事情都应该具备的一丝不苟的态度以及坚韧不拔的意志。在设计过程中大家团队合作,分工明确,以较高的效率完成了初步的设计。虽然以后我们将面临更多方面的挑战,比如单片机的编程、传感器技术的熟练运用等,但是相信我们一定能够继续以饱满的热情投入到这次作品设计中,以优异的成绩为我们的大学生活添上浓墨重彩的一笔!
* 本项目未获得作者开源授权,无法提供资料下载。
|