G02小组工作报告

一、              综述:

a)         项目名称:小车自动走迷宫;

b)        小组成员:

                        i.              周杰:负责总体规划,及ARM编程;

                      ii.              宋大成:负责车轮驱动;

                    iii.              陈潇:负责红外驱动;

c)         小车图片:

MicroMouse615

MicroMouse120

二、              项目介绍:

电脑鼠走迷宫竞赛的目的是制作一个微型机器人,它能在最短的时间内穿越迷宫到达终点。参赛的机机器人称为“电脑鼠”,将电脑鼠放入迷宫并启动操作的人称为“操作员”。

电脑鼠的基本功能是从起点开始走到终点,这个过程称为一次“运行”,所花费的时间称为“运行时间”。从终点回到起点所花费的时间不计算在运行时间内。从电脑鼠的第一次激活到每次运行开始,这段期间所花费的时间称为“迷宫时间”。如果电脑鼠在比赛时需要手动辅助,这个动作称为“碰触”。竞赛使用这三个参数,从速度﹑求解迷宫的效率和电脑鼠的可靠性三个方面来进行评分。器人称为“电脑鼠”,将电脑鼠放入迷宫并启动操作的人称为“操作员”。

G02小组的工作中,基本完成了电脑鼠的驱动部分和算法部分:电脑鼠可以进行直线行走、90度左转、90度右转和180度后转;能准确监测左前右三个方向的挡板,能准确判断左右间距是否恰当;能进行调距运动,以保持与左右挡板的距离;能简单判断通路,并计算记忆合适通路;并按照通路完成迷宫行走。

但是,由于某些原因,小车的没有取得完美的效果:由于电机转速控制不当,小车直线行走效果不佳(参看第条);左转右转不够准确,只能依靠调整函数补偿;算法不够优秀,正在探究更好的算法。这些问题都在努力克服中,我们不会因为检查完毕就放弃小车的调试。

三、              项目整体结构:

MicroMouse102 电脑老鼠,采用美国LuminaryMicro 公司生产的32 ARM CortexM3处理器LM3S102,控制和检测红外传感器;主CPU 根据检测到的传感信号,控制电机驱动电路调整行走路径,直到到达终点。

四、              硬件部分介绍:

LED 电路

电脑鼠有5 个独立的LED,通过LM3S 系统单片机的GPIO 口直接控制,如图 1.6 所示。电路采用了I/O 口灌电流的驱动方式来驱动LEDLM3S 系统单片机的灌电流为28mA(可配置),所以不需要驱动就可以点亮LEDGPIO 引脚输出高电平时LED 熄灭,低电平时LED 点亮。

电机驱动电路

电机采用直流减速电机,最高输出转速为800 /分钟,工作电压为DC3V。电机驱动

电路采用专用的单相直流电动机桥式驱动芯片。

车速检测电路

车速检测用于检测并记录车体运行的路径,通过车速检测记录车体做迷宫的坐标,同

时也起到控制车速和保持左右双轮的速度一致。

检测原理:在左轮和右轮的内则都贴有的光电码盘,码盘由两种颜色组成白色和黑色。

红外发射管安装在车轮光电检测码盘的检测区域,当红外发射与接收管正对着黑色边时,

红外线没有被反射,接收管的电阻很大;当红外发射与接收管正对着白色边时,红外线被

反射,接收管的电阻很小。

红外检测电路

红外检测电路是用于迷宫挡板的检测,分为左侧、右侧、前方三个方向,三个方向的

检测原理相同,某一个方向的检测电路。

CPU 及晶振电路

电脑鼠的单片机、晶体振荡器和LDO输出原理如图所示。该单片机选用LM3S102

微处理器。

五、              软件部分介绍:

一体化红外接收头工作原理

一体式红外线接收传感器IRM8601S,它内部集成自动增益控制电路、带通滤波电路、

解码电路及输出驱动电路。当连续收到38KHz 的红外线信号时,将产生脉宽10ms 左右的

低电平。如果没有收到信号,便立即输出高电平。Send 为发射控制端,高

电平时发射38KHz 的红外信号。Out 为接收输出端,低电平表示收到信号。

检测障碍物的软件设计

根据接收头是否检测到经过反射的红外线信号,就可以判断是否存在障碍物。由于接

收头检测到信号时只产生一个负脉冲,所以只需要在检测时使能红外线发射,一次检测结

束后使能无效,程序设计参考流程图如图2.5 所示。

接收头有一定的

响应时间

开始发送38KHz

的红外线

迷宫挡板检测

调制信号产生

本设计中采用定时器1 产生38KHz 的调制信号,由PB5 输出,该端口连接到图2.3

Pulse 端口。在中断中翻转PB5 输出信号,所以要产生频率为f 的脉冲,定时器的频率

要为2f。在本设计中要产生38KHz 的频率,定时器中断频率为76KHz

程序清单 3.1 为定时器1 的初始化函数,程序清单 3.2 为中断服务函数,在这里翻转

PB5 口输出状态。

程序清单 3.1 定时器1 初始化

void PULSEIni(void)

{

GPIODirModeSet(GPIO_PORTB_BASE, SEND | PULSE, GPIO_DIR_MODE_OUT); // 设置为输

GPIOPinWrite( GPIO_PORTB_BASE,SEND | PULSE,0); // 红外线初始时停止发射

SysCtlPeripheralEnable( SYSCTL_PERIPH_TIMER1 ); // 使能定时器1 外设

TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER); // 设置定时器1 为周期触发

TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet()/76000); // 设置定时器装载值

TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);

TimerEnable(TIMER1_BASE, TIMER_A);

IntEnable(INT_TIMER1A);

}

程序清单 3.2 定时器1 服务函数

void Timer1A_ISR(void)

{

TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT); // 清除定时器1 中断

GPIOPinWrite(GPIO_PORTB_BASE, PULSE,GPIOPinRead(GPIO_PORTB_BASE, PULSE) ^ PULSE);

// 翻转GPIO B5 端口

}

抗干扰处理

红外线在空气中传播和反射受外界的干扰,如果测量距离刚好处在能够检测到信号的

临界状态,保持距离不变,传感器输出信号也可能不确定。这样就需要在软件中进行抗干

扰处理。参考程序如程序清单3.3 所示。

程序清单3.3 抗干扰处理程序

GPIOPinWrite( GPIO_PORTB_BASE,SEND , SEND); // 发送脉冲

Delay(150); // 延时

for(i=0,j=0;i<10;i++) // 检测接收信号

{

if(GPIOPinRead(GPIO_PORTA_BASE, OUT_L)==0)

j++;

}

GPIOPinWrite( GPIO_PORTB_BASE,SEND , ~SEND); // 停止发送

if(j>5) // 左边存在挡板

{

}

else // 左边存在支路

{

}

3.1 为抗干扰程序在Micromouse 中运行后用逻辑分析仪抓到的波形图,Pulse

38KHz 的输出信号,Send 高电平有效,有效时发送红外线脉冲,OUT 为一体化接收头输

…… ……

出端,该图所示为接收头探测到障碍物,软件在Send 信号无效(下降沿)前完成检测OUT

输出信号,从图中可以看出,此时正处于OUT 有效信号的中间,所以软件里延时参数能

保证正确检测到信号。

3.1 传感器检测波形图

软件设计参考

为用一组红外实现两组参数(是否存在挡板和是否太接近挡板)的检测流程图。在Micromouse 中,用到了三组(左、前、右)反射式红外检测传感器,左边和右边的传感器各自都需要检测两组参数,而前方的传感器只需要探测有无挡板,存在挡板就必须根据策略转换行进方向,若不存在就可以继续前进。如图3.3 所示为Micromouse 红外检测的程序设计流程图。红外检测参考程序见程序清单 3.4 所示,该程序中使用了五个LED 用来指示传感器检测的状态,由于这几个LED 硬件上连接到JTAG,关于如何切换GPIOJTAG功能参见6 使用JTAG 引脚作GPIO

此频率仅作为参考,要根据实际检测距离来确定。结合可调电阻R1 变可以实现挡板和防碰撞的检测。

程序清单 3.4 Micromouse 红外检测函数(见附录)

电机的调速

电机的调速

直流电机的转速控制在本设计中通过PWM来控制,LM3S102 单片机则刚有两路PWM

输出,非常适合用于控制两个电机的转速。

两路PWM LM3S102 通用定时器0Timer0)的三种工作模式之一,16 PWM

式。该模式是将一个32 位的定时器,折分成两个16 位的定时器TimerA TimerB。这些

定时器为计数寄存器(GPTMTnR)递减计数,递减到0 时自动加载预装载值(GPTMTnILR)。

当然预装载值也是由用户设定,该直也就决定了定时周期,也即PWM 的输出周期。

当计数器的值与预装载值相等时,输出PWM 信号有效,当计数器的值与匹配寄存器

GPTMnMATCHR)的值相等时,输出PWM 信号失效。通过软件可以设定PWM 输的信

号有效和信号无效的电平状态。当GPTMCTL 寄存器的TnPWML 位值为0 时,信号有效

为高电平,信号无效为低电平;TnPWML 位值为1 时,则反之。如图 4.1 所示。

输出信号

计数

0x411A

0xC350

TnPWML=0

TnPWML=1

TnEN置位

GPTMTnR=GPTMnMR GPTMTnR=GPTMnMR

时间

4.1 16 PWM 模式输出

占空比的约定:占空比为在一个周期内,输出有信号有效电平占整个周期时间的比率。

在这里为以统一软件控制的约定,用户API 函数输入的占空比值越大,电机转速越快,正

向运行和反向运行都一样。

为了简化占空比输出的计算,将计数寄存器与匹配寄存器值相等时,输出的电平信号

为驱动电机的有效信号。例如将PWM 周期时间设定为60000 个时钟节拍,需要输出驱动

电机的占空比为75%,则设置匹配寄存器值为75*6000

由于电机的转向不一样,所以电机驱动的有效电平也需要调整,通过控制TnPWML

实现。

2 程序设计

Timer0 的两路16 定时器TimerA TimerB PWM 输出引脚分别为PB0 PB6PB0

PB6 分别控制左轮和右轮驱动器TA7291S IN1 引脚,而它们的IN2 引脚分别由GPIO

输出的PA4 PA5 控制。

左轮的控制函数如程序清单 4.1 所示。

该函数的第1 个参数sel 为选择轮子的控制方式:0 为停止,1 为轮子向前,2 为轮子

向后;percen 参数为占空比,其最大值为99,最小值为1,对于轮子的停止控制该参数无

效。

程序清单 4.1 左轮控制函数

void LeftWheelRun(int sel,unsigned char percen)

{

switch(sel)

{

/*轮子停止转动*/

case 0:

TimerDisable(TIMER0_BASE,TIMER_A); // 禁止定时器

GPIOPinWrite(GPIO_PORTA_BASE,LWC2,0xff); // 控制引脚输出高电平

GPIODirModeSet(GPIO_PORTB_BASE, LWC1, GPIO_DIR_MODE_OUT); // GPIO 输出

GPIOPinWrite(GPIO_PORTB_BASE,LWC1, 0xff); // GPIO 输出高电平

break;

/*左轮向前*/

case 1:

GPIOPinWrite(GPIO_PORTA_BASE,LWC2, 0xff); // PA4 输出高电平

TimerControlLevel(TIMER0_BASE,TIMER_A,true); // PWM 有效电平方向

GPIODirModeSet(GPIO_PORTB_BASE, LWC1, GPIO_DIR_MODE_HW); // PWM 输出

TimerMatchSet(TIMER0_BASE,TIMER_A,percen*600); // 设置占空比

TimerEnable(TIMER0_BASE,TIMER_A); // 使能定时器

break;

/*左轮向后*/

case 2:

GPIOPinWrite(GPIO_PORTA_BASE,LWC2, 0); // PA4 输出低电平

TimerControlLevel(TIMER0_BASE,TIMER_A,false); // PWM 有效电平方向

GPIODirModeSet(GPIO_PORTB_BASE, LWC1, GPIO_DIR_MODE_HW); // PWM 输出

TimerMatchSet(TIMER0_BASE,TIMER_A,percen*600); // 设置占空比

TimerEnable(TIMER0_BASE,TIMER_A); // 使能定时器

break;

}

}

右轮的控制函数如程序清单 4.2 所示。

该函数的第1 个参数sel 为选择轮子的控制方式:0 为停止,1 为轮子向前,2 为轮子

向后;percen 参数为占空比,其最大值为99,最小值为1,对于轮子的停止控制该参数无

效。

程序清单 4.2 右轮控制函数

void RightWheelRun(int sel,unsigned char percen)

{

switch(sel)

{

/*轮子停止转动*/

case 0:

TimerDisable(TIMER0_BASE,TIMER_B); // 禁止定时器

GPIOPinWrite(GPIO_PORTA_BASE,RWC2,0xff); // 控制引脚输出高电平

GPIODirModeSet(GPIO_PORTB_BASE, RWC1, GPIO_DIR_MODE_OUT); // GPIO 输出

GPIOPinWrite(GPIO_PORTB_BASE,RWC1,0xff); // GPIO 输出高电平

break;

/*右轮向后*/

case 2:

GPIOPinWrite(GPIO_PORTA_BASE,RWC2, 0xff); // PA4 输出高电平

TimerControlLevel(TIMER0_BASE,TIMER_B,true); // PWM 有效电平方向

GPIODirModeSet(GPIO_PORTB_BASE, RWC1, GPIO_DIR_MODE_HW); // PWM 输出

TimerMatchSet(TIMER0_BASE,TIMER_B,percen*600); // 设置占空比

TimerEnable(TIMER0_BASE,TIMER_B); // 使能定时器

break;

/*右轮向前*/

case 1:

GPIOPinWrite(GPIO_PORTA_BASE,RWC2, 0); // PA4 输出低电平

TimerControlLevel(TIMER0_BASE,TIMER_B,false); // PWM 有效电平方向

GPIODirModeSet(GPIO_PORTB_BASE, RWC1, GPIO_DIR_MODE_HW); // PWM 输出

TimerMatchSet(TIMER0_BASE,TIMER_B,percen*600); // 设置占空比

TimerEnable(TIMER0_BASE,TIMER_B); // 使能定时器

break;

}

}

需要注意的是,当PWM 信号禁止后,其输出引脚的电平状态是保持静止时的状态(可

能为低电平也可能为高电平),导致电机可能不能停止,所以在制停电机时,需要将PWM

引脚改为GPIO 输出,并且出高电平,使电机刹车停止。

定时器PWM 初始化函数如程序清单 4.3 所示。

程序清单 4.3 定时器PWM 初始化

void PWMTimer0AIni(void)

{

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // 使能定时器0

GPIODirModeSet(GPIO_PORTB_BASE, LWC1|RWC1 , GPIO_DIR_MODE_OUT);

/* 控制引脚输出*/

GPIOPinWrite(GPIO_PORTB_BASE, LWC1|RWC1 , 0xff); // GPIO 输出高电

GPIODirModeSet(GPIO_PORTA_BASE, LWC2|RWC2 , GPIO_DIR_MODE_OUT); // 控制引脚输出

GPIOPinWrite(GPIO_PORTA_BASE, LWC2|RWC2 , 0xff); // GPIO 输出高电

/* 定时器配置*/

TimerConfigure(TIMER0_BASE,TIMER_CFG_16_BIT_PAIR

|TIMER_CFG_A_PWM|TIMER_CFG_B_PWM); // 16 PWM 输出

TimerControlLevel(TIMER0_BASE,TIMER_A,false); //有效信号为低电

TimerControlLevel(TIMER0_BASE,TIMER_B,false);

TimerLoadSet(TIMER0_BASE,TIMER_A,60000); // 设定PWM 频率

TimerLoadSet(TIMER0_BASE,TIMER_B,60000);

}

Micromouse 车速检测

车速检测程序设计

本设计中选用了LM3S102 PA0 PB1 分别检测左轮和右轮的下降沿的脉冲个数,

为了快速向应检测信号,使用了下降沿触发中断。LM3S102 单片机的特点,任何一个GPIO

引脚都可以配置为中断输入,并且可以作任意设定为高电平触发、低电平触发、下降沿触

发、上升沿触发和上升或下降沿触发5 种模式。本应用中使用下降沿触发,其初始化如程

序清单 5.1 所示。

程序清单 5.1 轮子脉冲检测初始化

void WheelPulseIni(void)

{

// 配置引脚为输入

GPIODirModeSet(GPIO_PORTA_BASE, PULSE_R, GPIO_DIR_MODE_IN);

GPIODirModeSet(GPIO_PORTB_BASE, PULSE_L, GPIO_DIR_MODE_IN);

// 配置引脚下降沿触发中断

GPIOIntTypeSet(GPIO_PORTA_BASE,PULSE_R,GPIO_FALLING_EDGE);

GPIOIntTypeSet(GPIO_PORTB_BASE,PULSE_L,GPIO_FALLING_EDGE);

// 使能引脚输入中断

GPIOPinIntEnable(GPIO_PORTA_BASE,PULSE_R);

GPIOPinIntEnable(GPIO_PORTB_BASE,PULSE_L);

// 使能GPIO PA 口和GPIO PB 口中断

IntEnable(INT_GPIOA);

IntEnable(INT_GPIOB);

}

左右轮检测脉冲中断处函数如程序清单 5.2 所示。

程序清单 5.2 左右轮检测脉冲中断处函数

//------------------------------------------------------------------------------------

// 函数名称: GPIO_Port_A_ISR

// 函数功能: 右轮检测脉冲中断处函数

//------------------------------------------------------------------------------------

void GPIO_Port_A_ISR (void)

{

unsigned char IntStatus;

IntStatus = GPIOPinIntStatus(GPIO_PORTA_BASE,true); // PA 口中断状态

if(IntStatus&PULSE_R) // 是否为左轮脉冲中断

{

PulCount_R++;

if(PulCount_R >= RightPulse)

{

RightWheelRun(0, 1);

WheelStop_R= 1;

}

GPIOPinIntClear(GPIO_PORTA_BASE,PULSE_R); // 清中断

}

}

//------------------------------------------------------------------------------------

// 函数名称: GPIO_Port_B_ISR

// 函数功能: 左轮检测脉冲中断处函数

//------------------------------------------------------------------------------------

void GPIO_Port_B_ISR (void)

{

unsigned char IntStatus;

IntStatus = GPIOPinIntStatus(GPIO_PORTB_BASE,true); // PA 口中断状态

if(IntStatus&PULSE_L) // 是否为右轮脉冲中断

{

PulCount_L++;

if(PulCount_L>= LeftPulse)

{

WheelStop_L= 1;

LeftWheelRun(0, 1);

}

GPIOPinIntClear(GPIO_PORTB_BASE,PULSE_L); // 清中断

}

}

六、              系统DV:参看附件:

a)       直线行走3+右转:

该运动中,小车首先直线行走3格(50CM),然后右转,并在碰到障碍物后右转,直线行走一格,再右转一次;

b)       围绕小桌运动:

该运动中,小车围绕方形小桌绕圈,判断安全距离、检测是否存在通路,并自动修正方向。

七、              测试情况:

经检测,小车能较好的完成给定的运行任务,较为准确地直走、左右转,及180度转。小车完全可以完成探究迷宫、自动寻路等任务,并以较短的时间完成迷宫行走。

但是,小车依旧存在些问题:直走中有摆动现象,左右转也做不到90度(大概85度到95度之间),180度更不好;算法不够优秀,时间依旧较长。虽然这些问题更为琐碎更为难处理,但我们有信心,暑假间会完全克服。

八、       曾遇到的问题:

1.车轮行进速度不一:

       同一函数中,小车的左右转速相差比较大,我们尝试采取了以下几种方式解决

       1)。调占空比:无效,原因不明。在与别的小组交流之后,我们尝试改写了原先的驱动函数,使速度函数与正反转函数区分开:

 

(原函数 & 改进后的函数 请见附录)

 

还不太明白是为什么,把两个函数分开写了之后,发现有一定效果。

 

       2)。脉冲补偿:

       这也是演示程序的方法,在执行完一次运行任务之后,把相差的脉冲补偿到下一次任务的设定中:

 

       PWMTimer0AIni();                            // PWM初始化

       PULSEIni();                               // 调制信号初始化

       WheelPulseIni();                         // 测速初始化

       while(1)

       {

            LeftPulse = 10;                           // 设定电机运行任务

            RightPulse = 10;

            WheelStop_L = 0;                       // 清零电机停止标志位

            WheelStop_R = 0;

            LeftWheelRun(1, 99);                  // 启动左右电机

            RightWheelRun(1, 99);

            while(!(WheelStop_L && WheelStop_R))// 等待运行结束,状态在中断中改变

                    Check_Infrared(0);               // 等待过程中进行红外检测

            PulCount_L -= LeftPulse;                    // 误差补偿到下一次运动中

            PulCount_R -= RightPulse;  

       }

 

       想法很好,实际行不通。

       以最低误差来算,假设左轮10个脉冲,右轮9个,小车明显走出一条弧线;而当下次补偿到下次之中时,小车还是先走同样的路程,然后左轮停转,右轮转2个脉冲(上次误差+ 这次误差),表现出了明显的“一瘸一拐”的情况;而且,在我们的调试过程中,出现了不稳定的左右摆动,这是由于“半个脉冲”的问题,小车不能有效识别比较小的距离差,在最好的状态下,小车也存在计数的问题,比如,左轮刚转就开始向下的触发,右轮快转一圈才有第一次的向下触发。而且,这种误差是随机的,与小车车轮的起始位置有关,不好避免。

      

       3.从硬件下手:

       在左右电机同加固定电压时,清楚地看到转速不一样,因此,最好的办法还是从硬件上下手,通过串联电阻来解决问题。这是我们的一个想法,还没开始实施,准备在暑假时再想想软件解决办法,不行就改电路。(电机内阻,运行时电流)

 

2。检测信号的波形:

       受灯光的影响,可以看到,红外接受得到的波形不时很好。检测初速的还好,因为幅度比较大,所以没有误判的问题;检测挡板的波形振动比较大。按照电路图,尝试着变换的电阻,取得不错的效果,以下函数足够完成判断:

 

源程序详见附录)

             

3。编译器的问题:

       大量铁的事实证明,crosswork不好用,推荐使用Keil for ARM。前期使用的是crosswork,很多不明就里的问题,换到Keil for ARM就解决了,说明crosswork对小车的支持不够好。很多函数,在crosswork上,完全起不到效果,跑出来都知道是怎么回事。我们不是在责怪crosswork不好,但至少说明,不易于上手。

       总结了一些发现的问题:

       1)。不能出现汉字:还好,无非就是存盘载入时麻烦点。

       2)。只能装C盘:刚开始装在D盘,整天蓝屏。

       3)。头文件载入:很多头文件需要手动一一载入,还是查百度知道的,说明文件上没有。

       4)。编译显示错误,不显示为什么错:开始时,发现错误就在Keil上找错。。。。。。

       5)。脱机运行问题:想脱机运行?需要改很多。。。。。。

       因此,不推荐用crosswork

 

八、              心得体会:

a)         辛苦:在刚着手时,一点头绪没有。于是从单片机、电路图、红外与电机一点点看,为了一个小车重新学了很多东西;后来接到小车,开始忙着调试写程序,面临着很多的问题。由于没有足够的资料,三人齐心协力一点点地摸索着走。经历过一连几天夜夜23点,也有过一整天三份外卖一起叫的时间。由于我们对自己的要求特别高,所以在每一个小的细节上都力求完美,花费了很多时间精力。

b)        兴趣:与别的课程不一样的地方,电脑鼠非常的好玩,有点像小时候的四驱车,但多了的是科技含量。看着小车在手中逐渐的成长,探路行进等功能一一实现,心中的好奇与兴奋是很难说的清的。因为兴趣,所以很多的辛苦都可以忽略不计,很多的焦头烂额也都能谈笑而过。

c)         荣耀:最喜欢做的一件事,是把小车打开,让他在寝室里自己逛着玩。没养过小孩,但相信看着自己的孩子一点点学会走路的感觉,和我们看小车的感觉一样。也许正是因为我们比别的组走过更艰难的路,所以在取得小小成绩后比别人更为的骄傲。现在的小车已经能完成基本任务了,我们期待着他能早点的大学毕业~~~~~~~~~

 

最后,我们在此要感谢每一位队友的努力与付出,感谢兄弟间的团结与友爱;我们也要感谢其余小组给与的帮助,彼此的交流帮助我们更好的进步;感谢助教的指导,在ARM的编程中给我们指出了最重要的方向;我们当然更要感谢张老师的教导,感谢张老师对我们错误的包容指教,和提供的广阔的学习空间。在暑假的日子里,我们会再接再厉,一定会在竞赛中取得成绩!

 

 

                                                                                                  G02小组全体成员

                                                                                                                2008/7/7