Posts Tagged ‘乐高’

解魔方的机器人攻略27 – 让萝卜头开口说话

上次提到了“甜美的声音”,今天介绍一下如何让萝卜头发出声音。NXT的发声装置就是盒子上那个小喇叭,因为喇叭质量不是很高,所以别太指望萝卜头能演奏世界名曲。从开发角度来说,NXT内置了很多种发声的方式,详细内容可以参考leJOS中文教程 – 播放声音。例如,我们用下面的代码就可以让NXT蜂鸣两声:

Sound.twoBeeps();

NXT还可以直接播放8位的wav文件,播放命令是:

Sound.playSample(new File("Start.wav"));

下面介绍一下如何制作这样的wav文件。

首先要录制声音,用手头的任意录音工具都可以,例如手机,mp3,其实电脑本身也可以录音。萝卜头一共需要三句台词:“开始”、“结束”和“出错啦”。可以一次录完,把三段声音录在一起,每句台词之间留一点停顿,后期容易裁剪。

录好音之后,一般会生成*.wav或者*.mp3的文件。这种直接录好的文件一般都是双声道,而且采样频率比较高。这种高级音频萝卜头是没法识别的,要适当压缩成萝卜头可以处理的格式。

强烈推荐一款叫“CoolEdit”的音频处理工具,打开录好的音频文件,可以看到有声音的部分是波形图,中间停顿的部分几乎是平的直线。可以用鼠标拖动选择相应的音频,然后在菜单中选择“选中部分另存为..”,保存的格式选择“Wave PCM unsigned 8 bit,8000HZ,64kbps,单声道”,就可以生成相应的wav文件了。最后可以生成以下三个文件:

Start.wav
End.wav
Error.wav

下面把这几个文件下载到NXT中,在命令行中运行:E:\lejos_nxj\bin\nxjbrowse.bat。如果萝卜头开机的话,这个工具的“download”功能,依次把三个文件都保存到NXT中。

最后在程序的相应地方加入播放代码即可,上一篇中已经看到了出错信息的播放,“开始”和“结束”的播放程序为:

if(hasCube && isChaotic)
{
	//The cube is read, init the error status
	hasError = false;

	//Play some sound to notice the "Start"
	Thread.sleep(1000);
	Sound.twoBeeps();
	Thread.sleep(1000);
	Sound.playSample(new File("Start.wav"));

	//Ignore solve cube codes......

	if(!hasError)
	{
		//The cube has been solved
		isChaotic = false;

		Sound.playSample(new File("End.wav"));
		Thread.sleep(1000);

		//Rotate the cube two circles for annoucement
		Robot.RotateBottom(8);
	}
}

解魔方的机器人攻略25 – 解魔方

现在我们的工作已经接近尾声了,看看怎么把电脑变成一个NXT的蓝牙遥控器。这个部分大家其实可以自由发挥,我设计的数据通讯流程是这样的:

1,蓝牙连接成功
2,NXT扫描魔方,发送6个面,每个面9块共54组颜色数据到电脑
3,NXT发送一个字节(0xFF)到电脑,表示颜色读取完毕
4,电脑开始计算解法,得到解魔方的步骤,一共N步
5,电脑发送一个字节N到NXT
6,NXT进行从1到N的循环,每次发送一个字节n到电脑,请求第n步操作
7,电脑发送第n步操作给NXT
8,NXT执行完全部N个操作,发送一个字节(0xFE)到电脑,通知解魔方完成
9,电脑清空步骤和颜色数组,准备迎接下一次任务
10,按下Escape按钮,NXT发送三个(0XFF)给电脑,关闭蓝牙连接并退出

同学们松了一口气,核心算法都搞定了,这点任务算啥,准备十分钟交卷吧。。。。

且慢,我们得到的步骤是类似F1 U2 F2 D3 L2 D1 F1 U3 L2 D1这样的序列,但是萝卜头永远只能旋转最下面一层,怎么办?

这个也简单,把相应的面翻到底面就好了,毕竟萝卜头的胳膊也不是个摆设。

问题又来了,第一步F1时,把F变成了底面;这时候魔方已经经过了某些翻转操作,那么第二步U2该转哪一面呢?这下有点麻烦了…

如果每次都还原到原来的位置,会增加非常多的步骤。

最好的方法是每次都通过最近的路径把需要旋转的面翻到最底层,然后旋转它。

所以我们需要保存一个坐标系,在翻转魔方的时候,让这个坐标系永远跟魔方的真实位置同步,请看CenterColor类,用来记录六个面的中心位置:

public class CubeCenter
{
    public string[] CenterColor = new string[6] { "U", "R", "D", "L", "F", "B" };

    public void RotateBottom(bool colockwise)
    {
        if (colockwise)
        {
            string n = CenterColor[5];
            CenterColor[5] = CenterColor[1];
            CenterColor[1] = CenterColor[4];
            CenterColor[4] = CenterColor[3];
            CenterColor[3] = n;
        }
        else
        {
            string n = CenterColor[5];
            CenterColor[5] = CenterColor[3];
            CenterColor[3] = CenterColor[4];
            CenterColor[4] = CenterColor[1];
            CenterColor[1] = n;
        }
    }

    public void RotatePaw()
    {
        //Only can move forward
        string n = CenterColor[0];
        CenterColor[0] = CenterColor[3];
        CenterColor[3] = CenterColor[2];
        CenterColor[2] = CenterColor[1];
        CenterColor[1] = n;
    }

    public int FindCenter(string position)
    {
        int center = -1;
        for (int i = 0; i < 6; i++)
        {
            if (CenterColor[i] == position) center = i;
        }
        return center;
    }
}

有了这个参考坐标系,我们就可以把URDLFB表示法的解魔方步骤,转化成萝卜头能识别的PBS表示法。嗯,不用去Google搜索,这个PBS表示法是我发明的(也就是瞎编的^_^ ),它表示
P: Paw 爪子翻动一次
B:RotateBottom 从底面旋转魔方,后面需要接一个1~3的数字
S:RotateBottomSide 旋转魔方的底面,跟B的区别是这时候爪子抓住上两层,然后旋转底面

下面这段代码描述了从URDLFB操作到PBS操作的转换:

int findSidePosition = CenterStatus.FindCenter(targetSide);

//Rotate to corrent bottom
switch (findSidePosition)
{
    case 2:
        //Do Nothing
        break;
    case 1:
        CenterStatus.RotatePaw();
        Steps.Add(new MoveStep(MoveType.RotatePaw, 0));
        break;
    case 0:
        CenterStatus.RotatePaw();
        Steps.Add(new MoveStep(MoveType.RotatePaw, 0));
        CenterStatus.RotatePaw();
        Steps.Add(new MoveStep(MoveType.RotatePaw, 0));
        break;
    case 3:
        CenterStatus.RotateBottom(true);
        CenterStatus.RotateBottom(true);
        Steps.Add(new MoveStep(MoveType.RotateBottom, 2));
        CenterStatus.RotatePaw();
        Steps.Add(new MoveStep(MoveType.RotatePaw, 0));
        break;
    case 4:
        CenterStatus.RotateBottom(true);
        Steps.Add(new MoveStep(MoveType.RotateBottom, 1));
        CenterStatus.RotatePaw();
        Steps.Add(new MoveStep(MoveType.RotatePaw, 0));
        break;
    case 5:
        CenterStatus.RotateBottom(false);
        Steps.Add(new MoveStep(MoveType.RotateBottom, 3));
        CenterStatus.RotatePaw();
        Steps.Add(new MoveStep(MoveType.RotatePaw, 0));
        break;
}
Steps.Add(new MoveStep(MoveType.RotateBottomSide, Convert.ToInt32(rotateCount)));
Steps[Steps.Count - 1].OrginStep = currentStep;

下面是一个PBS表示法的步骤示例,基本上一个URDLFB旋转操作,会对应1~3个PBS操作:
P B3 P S2 B1 P S1

为了减少发送的数据量,我们用下面的规则来发送PBS表示法的步骤,每个步骤用一个字节来描述:

switch (MoveType)
{
    case MoveType.RotatePaw:
        return (byte)10;
    case MoveType.RotateBottom:
        return (byte)(20 + Count);
    case MoveType.RotateBottomSide:
        return (byte)(30 + Count);
    default:
        return (byte)0;
}

在NXT上对应的解析操作是:

//Get result
int step = BlueTooth.ReadBytes()[0];
if(step==10)
{
	//Rotate paw
	Robot.RotatePaw();
}
else if(step>=20 && step<30)
{
	//Rotate Bottom
	int count = step - 20;
	if(count == 3) count = -1;
	Robot.RotateBottom(count);
}
else if(step>=30 && step<40)
{
	//Rotate Bottom Side
	int count = step - 30;
	if(count == 3) count = -1;
	Robot.RotateBottomSide(count);
}

开始编译工程,佛祖&上帝&安拉&比尔盖子同时保佑,程序编译通过了。如果运气好的话,蓝牙连接成功以后,萝卜头就可以顺利解魔方了。

好了,所有的代码都介绍完了,之后还会介绍一些收尾和改进的工作,主要包括:
1,用超声波测距传感器(就是那对眼睛)制作“开关”;
2,读色错误,卡住等情况的异常处理
3,语音提示,让萝卜头开口说话
4,暂停功能,帮助我们进行调试

解魔方的机器人攻略20 – 修正电机误差

在上一篇攻略中,我们使用了一些角度的配置信息,例如:

//the motor angle for paw to hold the cube
static int PawHoldPosition = 56;
//the motor angle for paw to rotate the cube
static int PawTurnOverPosition = 110;

这些用于Motor.rotate(n)的角度,都是相对于电机的原始位置而言的。在我的代码里,初始位置是这样定义的:

颜色传感器和魔方底座的初始位置

颜色传感器和魔方底座的初始位置

爪子的初始位置

爪子的初始位置

在最初的版本里,我是在断电状态下,手动把电机拧到指定的初始位置。(程序一旦开始运行,角度信息就已经开始记录了,而且拧电机会有很大的阻力)
随后问题就来了,如果初始位置不准确的话,那么必然会导致旋转之后的位置不准确。其中最省心的是爪子的初始化位置,因为它是贴在后支架上,这个参照物非常稳定。

颜色传感器的杆很长,目测很难判断是否已经平行。魔方底座更是转十几次以后,误差越来越大。所以我们需要一段程序,把稍有偏差的初始位置纠正回来。

首先看一下如何修正魔方底座的误差。我们曾经介绍过,在魔方底座的下方安装了一个亮度传感器,当底座在某些位置的时候,会挡在亮度传感器的上面,再转过一定角度,就又把它露出来。亮度传感器有一个红色的小灯,可以通过light.setFloodlight(bool);来点亮或者关闭它。通过对比点亮和关闭前后的读数差,就可以判断出底座什么时候被挡住(在底座的下方需要贴一圈白纸,增强反光)。读数的曲线图是这样的:

读数的示意图

读数的示意图

也就是说,随着传感器被慢慢的挡住,这个亮度差值会越来越大,理论上最大值就是被挡住的中心位置。考虑到传感器的读数是有误差的,所以不能只取一个最大值点来计算,需要设置一个阀值,把最大的N个点都找到,那么它的中心位置就比较准确了。

//Fix the position of cube base
public static void FixBasePosition() throws Exception
{
int step = 3;
int tolerance = 4;
light.setFloodlight(false);
bottom.rotate(-50);
int angle = 0, minLight = 10000;
int realtimeLight = ReadLightDifference();
while(realtimeLight < minLight + tolerance)
{
bottom.rotate(step);
realtimeLight = ReadLightDifference();
if(realtimeLight < minLight)
{
minLight = realtimeLight;
angle = 0;
}
else
{
angle += step;
}
}
bottom.rotate(- angle/2 - FixBasePositionOffset);
}

//Read the light difference between light on and light off
private static int ReadLightDifference() throws Exception
{
int l1 = 0, l2 = 0;
l1 = light.readValue();
light.setFloodlight(true);
Thread.sleep(20);
l2 = light.readValue();
light.setFloodlight(false);
return l1-l2;
}

可以测试一下,把魔方底座手动拧歪一个小角度(正负十几度^_^),运行这段代码之后,底座会还原到和爪子平行的位置。

颜色传感器的位置修正比较简单:让它慢慢的靠近魔方,在传感器下方遇到魔方之前,它的读数都是0。所以一旦发现有读数,我们让它返回32度,就回到了爪子平行的位置,这个度数通过几次实验就可以试出来。

//Fix color sensor position
  public static void FixColorSensorPosition() throws Exception
  {
   int tolerance = 5;
   ColorMotorBaseAngle = -25;
   monitor.rotateTo(ColorMotorBaseAngle);
   Thread.sleep(100);
   monitor.setSpeed(50);
   int r = color.getRawRed();
   int g = color.getRawGreen();
   int b = color.getRawBlue();
   int baseColor = r + g + b;
   int TargetExists = 0;
   while(TargetExists < baseColor + tolerance && ColorMotorBaseAngle > -50)
   {
    monitor.rotateTo(ColorMotorBaseAngle--);
    r = color.getRawRed();
    g = color.getRawGreen();
    b = color.getRawBlue();
    TargetExists = r + g + b;
   }
   monitor.rotateTo(ColorMotorBaseAngle + 32);
  }

下面也做一个实验,把颜色传感器的位置拧歪,它也能回复到指定的位置。点此下载这个例子的全部代码。实验方法为:按Left键修正魔方底座位置,按Right键修正颜色传感器位置,按Escape键退出

时间仓促,每次贴的功能都不多,下一次介绍如何把魔方的颜色读取到数组中。

解魔方的机器人攻略11 – 爪子

这次不说废话了,直接上图,节约时间:

一大堆散件

一大堆散件

组装起来

组装起来

横杆加固,另外点缀些颜色

横杆加固,另外点缀些颜色

一组连杆,注意蓝色的那根需要磨得薄一点

一组连杆,注意蓝色的那根需要磨得薄一点

组装好的连杆

组装好的连杆

与悬臂的连接

与悬臂的连接

大体框架已经搭成了!

大体框架已经搭成了!

加个小人点缀一下

加个小人点缀一下

解魔方的机器人攻略10 – 爪子电机

今天刚刚听说lego有一个叫做LDD的软件,可以直接生成搭建图。三人行必有我师,在这里感谢一下程序猎人

真是应了一句老话“独学而无友,孤陋而寡闻”。从我决定开始做魔方机器人以来,基本上都是自己闭门造车。后来为了发攻略,又重头搭建了一遍,途中拍了无数照片。早知道就不费这个牛劲了,更郁闷的是搭完以后程序员的兽性大发,改了n多地方和无数代码。。。。

不过话说回来,牛劲既然已经费了,我还是坚持把这一系列照片发完,嘿嘿。大家先凑合看,如果有时间的朋友愿意帮我转成LDD的搭建图,本人将不胜感激。

下面是萝卜头小爪子的驱动电机搭建过程:

准备一个电机

准备一个电机

连接电机轴,引出动力

连接电机轴,引出动力

几个连接件

几个连接件

不知道该说啥,照葫芦画瓢吧

不知道该说啥,照葫芦画瓢吧

这是下面的支架

这是下面的支架

和大底盘的对接过程

和大底盘的对接过程

看!搭起来了,请注意这里的角度和距离都是计算过的,最好不要变化

看!搭起来了,请注意这里的角度和距离都是计算过的,最好不要变化

这是两个悬臂,其实一个就可以了,两个是为了结实点,也更好看

这是两个悬臂

连杆的安装位置

两个悬臂的安装位置

悬臂安装以后,为了更结实,又增加了一个

悬臂安装以后,为了更结实,又增加了一个

安装完成了

安装完成了

绕到后面看一眼

绕到后面看一眼

这个版本的爪子电机,可以看出是由电机直接连转轴驱动的。在很多次朋友参观的过程中,这个爪子由于力气不够大,被魔方卡住了,让我感到非常没有面子(算了,萝卜头表现欠佳,归根结底还是我没培养好)
下面就是兽性大发的部分了:改用了一对3:1的齿轮组,把萝卜头的臂力增强了3倍,所以现在彻底解决了爪子被卡住的问题。搭建过程没有再拍照了,只能看看结果照片,大家自由发挥吧:

添加了减速齿轮组的爪子电机

添加了减速齿轮组的爪子电机

换个角度来个特写

换个角度来个特写

解魔方的机器人攻略9 – 颜色传感器电机

接下来的任务是安装驱动颜色传感器的电机。为什么我们要把这这部分安装在斜面支架上呢?因为颜色传感器是用来读魔方颜色的,按照说明书的要求,读数时必须距离2~3厘米,并垂直于目标物体的表面。所以魔方是斜的,传感器也必须是斜的。

有人给我提意见,怎么每次都只更新这么一点,一次多发点吧。

其实帖子就像姑娘的裙子,太短了盖不住主题,太长了又没有吸引力,差不多就行啦:)

之前我试过发特别长的攻略,我家娘子打开页面的时候,被不断缩短的滚动条吓的手一哆嗦。。。。又关掉了。。。

下面进入正题:

准备一个延长杆和一个直角连杆

准备一个延长杆和一个直角连杆准备好电机和一些连接件

准备好电机和一些连接件

准备好电机和一些连接件

神奇吧,电机正好连上,不过还有点晃晃悠悠的

神奇吧,电机正好连上,不过还有点晃晃悠悠的真是两个加固的小件

这步有点费解,刚才的两个小件是加到了连杆的下面,另外因为件不够了,我把上面的普通横杆换成了疙里疙瘩的连杆

这步有点费解,刚才的两个小件是加到了连杆的下面,另外因为件不够了,我把上面的普通横杆换成了疙里疙瘩的连杆

准备延长底座,一直要延伸到爪子那边

准备延长底座,一直要延伸到爪子那边

延长后的底座,正好顺路看看刚才比较费解的电机连接部分

延长后的底座,正好顺路看看刚才比较费解的电机连接部分

这一部分拍的照片有点少,不过乐高积木就是有这点好处,你想怎么蹂躏它都可以,只要接在一起就可以了,不一定非要完全按照我的接法。下一篇我们将要连上驱动爪子的电机!

解魔方的机器人攻略8 – 底座电机

底座完工以后,需要把它连接到电机上。需要注意的是,我们还需要把这个底座变成一个40度左右的斜坡。为什么要有坡度呢,肯定不是吃饱了撑的。因为萝卜头只有一个爪子用来翻转魔方,有了坡度以后,借助重力作用,轻轻一推就可以翻过去。
经过我多次实验,坡度太大的时候魔方容易滚出台外,坡度太小了又翻不过去,这个40度左右刚刚好。

说起这个,我想起前不久的老同学聚会,有些同学太“爽快”,聚会非要喝到人仰马翻为止。其实任何事物都要掌握一个度,所谓“酒饮微醉,花看半开”。不喝酒没气氛,喝多了太伤身,还鬼哭狼嚎的。。。就像这个斜坡似的,恰到好处最合适。

又扯远了,先远观一下我们即将要做的部分(下图的右边部分)

接下来要介绍右侧的电机和斜坡支架

接下来要介绍右侧的电机和斜坡支架

好,接下来继续看图说话:

在底盘背面加上四个转向固定连杆

在底盘背面加上四个转向固定连杆

插上以后的效果

插上以后的效果

电机连接需要的配件

电机连接需要的配件

电机连接效果

电机连接效果

后来发现那个大直角插件有问题,换成黄色的这个了,懒得再拍一遍,凑合看吧

后来发现那个大直角插件有问题,换成黄色的这个了,懒得再拍一遍,凑合看吧

连上以后的效果,领会精神吧,自己试试

连上以后的效果,领会精神吧,自己试试

支架需要的配件

支架需要的配件组装后的支架

我最爱的转向“插销”,又结实又好用

我最爱的转向“插销”,又结实又好用

支架和电机连接

支架和电机连接

加一个蓝色插销加强一下

加一个蓝色插销加强一下

连上一个大直角,这个是以后用的,先放着

连上一个大直角,这个是以后用的,先放着

准备做另一边的支架

准备做另一边的支架

组装后的第二个支架

组装后的第二个支架

支架与电机连接

支架与电机连接

这些是固定宽度的撑杆

这些是固定宽度的撑杆

这个支架还没有完全连起来,给它添加一个直角连接,连接的照片忘拍了,自己试试吧

这个支架还没有完全连起来,给它添加一个直角连接,连接的照片忘拍了,自己试试吧

完工了!看看四脚朝天的效果图

完工了!看看四脚朝天的效果图

解魔方的机器人攻略7 – 底座

接下来的几篇攻略会以图片为主,基本上每个步骤都加上了下一个步骤需要的颗粒,相信聪明的你肯定能理解。
首先要制作的是魔方的底座,就是下面这个东东:

可选择的魔方底座

可旋转的魔方底座

(我家娘子看了上面这张图,第一反应是“结婚戒指呢?”。哭,好不容易找的角度,居然被慧眼如炬的识破了……:)
下面是看图说话环节:

双层的齿轮盘+两个连杆

双层的齿轮盘+两个连杆

这个是背面,接上转向连接件

这个是背面,接上转向连接件

没啥好说的

没啥好说的

装上了“擂台的四个柱子”

装上了“擂台的四个柱子”

这些将是“擂台的围栏”

这些将是“擂台的围栏”

两个围栏的最后合影,从此天各一方

两个围栏的最后合影,从此天各一方

另外两个围栏

另外两个围栏

四面围栏搞定,准备开始铺地砖

四面围栏搞定,准备开始铺地砖

定位销钉

定位销钉

这是几块“地砖”

这是几块“地砖”

继续铺地砖

继续铺地砖

地砖安装前

地砖安装前

大功告成,看看效果

大功告成,看看效果

两点说明:
1,这样装完的底盘是有沟壑的,翻转魔方的时候会有很大摩擦力,需要铺上一层光滑的纸或塑料;我从零食盒上剪了一块方形的塑料贴上了。
2,就在我制作的过程中,国甲魔方出了第二代,比标准的魔方小一点,为56mm(标准Rubik’s是57.15mm)。因为这一点点误差,萝卜头回国以后一直水土不服,直到我把四周的护栏缩小了一圈。各位同学到时候请根据自己买的魔方来做相应调整。

这是最近的样子:

调整后最新的样子

调整后最新的样子

解魔方的机器人攻略2 – 选择方案

有了想法,接下来该怎么行动呢?我建议的方式是:
考查 -> 确定方案 -> 架构 -> 实现 -> 改进

我们先开始考查,随便Bing一下 rubik+cube+robot 。你可以找到各种奇奇怪怪的魔方机器人,例如:

各种神奇的魔方机器人(无聊的人还真不少)

各种神奇的魔方机器人(无聊的人还真不少)

需要链接的请点这里:
http://www.switched.com/2009/09/17/teens-rubiks-cube-robot-solves-classic-puzzle/
http://video.google.com/videoplay?docid=-2084071621500271233#
http://www.youtube.com/watch?v=jkft2qaKv_o
http://www.engadget.com/2007/12/17/kawasaki-robot-solves-rubiks-cube-in-six-seconds-flat/
http://tiltedtwister.com/

我决定参考(请注意是参考而不是抄袭)图中左下的方案,该方案基于Lego公司的NXT Mindstorm机器人套装制作,有以下优点:
1,成熟产品,无需设计电路和焊接
2,积木式设计,扩展性超强
3,三组电机,多种传感器,蓝牙连接,功能很完善
4,有很多第三方的开发包,编写代码很方便
5,价格可以承受(2k左右)

它的缺点:
1,个头小,功率不高,转魔方没问题,干重体力活就不行了
2,塑料连接件,容易出现误差
3,想进一步扩展电子设备较困难

万丈高楼平地起,确定方案就是迈出了第一步!请注意:貌似最轻松的这一步恰恰是最关键的,因为它会影响到之后的所有工作。这个考查阶段,我大概用了一星期的时间查阅资料,对比和估算了各种方案需要的时间和经费;另外还需要一个大概的可行性分析,确定这个方案可以行的通。

现在回过头来看,可行性分析非常重要但也不要钻牛角尖,因为做一件事很少能一帆风顺,总会遇到各种出乎意料的问题。只要不轻言放弃,开发人员永远都可以兵来将挡,水来土掩。

接下来就准备掏银子采购吧,像泡妞一样,该出手时就出手!

解魔方的机器人攻略1 – 前因后果

在开始介绍方案之前,我先回答一个问题。有人问我,为什么你无端端的会想起做一个解魔方的机器人呢?

(嗖~~镜头切换到1990年)
玩具店里,一个小P孩正呆呆的看着一架模型飞机。他的眼睛里充满了渴望,小伙儿追求姑娘的眼神也不过如此。
但是他没有哭闹着要买,因为他知道家里没有多少钱(哈哈,这娃真懂事啊)
最后他挑了一个很便宜的魔方,这个魔方成了他几年内唯一的玩具。
那个时代没有网络,信息匮乏,这个不算聪明也不算太笨的小P孩,自己一个人闷头玩了两年,终于找到了还原的方法。

(嗖~~镜头又切换到1996年)
在座如果有北航的校友,应该知道冯如杯科技制作竞赛,每年各系都有老师组织并指导学生参赛。
航空发动机系的新生:老师,我想做一个能转魔方的机器人
指导老师(观察中:这个学生真是特别啊–看上去特别呆):
嗯,你的想法非常好,不过我觉得实现起来很难,而且没有什么实用价值,另外咱们系也没多少经费……
于是这个不切实际的想法就这样被咔嚓了。
题外话:其实当时计算机还在Dos时代,Internet更是还没在北京出现,做这样的机器人确实非常困难。我后来参加的Atar9C发动机实体模型项目,获得了冯如杯的二等奖。
这个发动机至今还展览在北航三号教学楼的发动机陈列室里,回想起来还是无法抑制的臭美啊!

(镜头再次切换)
某公司老板酷爱长跑,为了迎接新加坡马拉松大赛,他组织了一次公司内的热身长跑活动。
在这次活动里,只要跑完20公里,就可以获得几百大洋的奖金。
有一位年轻人恰好出差到此,跑两小时就有几百大洋入账,不赚白不赚啊!
不幸的事情发生了,半路上他亲眼目睹了一个同事倒下,心脏病突发。
虽然这种事在长跑中很常见,虽然和这位同事素不相识,但是年轻人还是被震撼了
人生如白驹过隙,你曾经想过要做一些事情,但是“有空了再说吧”,“有钱了再说吧”。。懒人的借口总是好找的。
当然,大多数人不会以这种突然的方式离去,他们只是在不知不觉中变老,然后有一天,他们会“突然”发现自己没多少时间了。
所以他决定做点事情,从十多年前被鄙视的小心愿开始做起。
题外话:世事就像变幻莫测的魔方,一串貌似毫不相关的因,可能会结出一个莫名其妙的果。这就是传说中的蝴蝶效应吧!