Posts Tagged ‘机器人’

解魔方的机器人攻略19 – 让魔方动起来

一星期没更新,原因就不多说了,总之请见谅。从今天开始继续发攻略 :)

我原来的代码又多又乱还没有注释,自己看着都眼晕,找点代码晕的跟坐过山车似的。现在正在把它们重新整理优化,再加上注释。我打算整理一部分就发一部分攻略,攻略发完了也就整理完了。另外,这几天有很多网友正帮忙翻译lejos的中文教程,我在整理的过程中也学到了不少东西,有兴趣的同学还可以加入。

下面开始正题。假设现场的观众们按照前面的攻略,已经把萝卜头搭建好了。第一段程序先让魔方能动起来,实现的功能是:

  • 按Left键,魔方底座旋转90度
  • 按Right键,爪子抓住魔方,然后底座带动最下面的层旋转90度
  • 按Enter键,爪子把魔方翻转90度
  • 按Escape键,程序退出

下面介绍需要用到的一些知识点

1,创建传感器和电机的实例:

//Define Sensors
 static UltrasonicSensor distance=new UltrasonicSensor(SensorPort.S1);
 static LightSensor light = new LightSensor(SensorPort.S2);
 static ColorSensor color = new ColorSensor(SensorPort.S3);
 //Define Motors
 static Motor paw=Motor.A;
static Motor monitor=Motor.B;
 static Motor bottom=Motor.C;

这部分对应的是我们的接线方式:
传感器1口接超声波传感器,也就是眼睛
传感器2口接亮度传感器
传感器3口接颜色传感器
电机A口接爪子的电机
电机B口接颜色传感器的电机
电机C口接魔方底座的电机

2,创建一个Robot类,这个类用于控制机器人结构上的各种动作,下面三个方法分别对应上面说的三个功能:

public static class Robot
{
 public static void RotateBottomSide(int nQuarter)
 {   }

 public static void RotateBottom(int nQuarter)
 {   }

 public static void RotatePaw()throws Exception
 {   }
}

这里使用了关键字static,因为萝卜头只有一个实例,所以把它设置成静态类。静态类可以直接使用静态方法,不需要创建实例,还是看一段代码对比下:

//创建实例的用法
Robot instance = new Robot();
instance.rotate();
//静态类的用法
Robot.rotate();

3,设置了一些参数

//如果爪子部分改装了那个3:1的减速齿轮,设置成true,不明白的请看 http://www.diy-robots.com/?p=147 最后两张图
 static boolean HasReducer = true;
 //爪子抓住魔方时的电机角度
 static int PawHoldPosition = 56;
 //爪子翻动魔方时的电机角度
 static int PawTurnOverPosition = 110;
 //底座旋转90时,电机的旋转角度(因为齿轮组的原因)
 static int BaseOneQuarter = 315;
 //当底座旋转魔方底面时,因为魔方的阻力,需要先多转一个小角度,然后再转回来,这是用来修正误差的角度
 static int BaseRotateFix = 40;

4,控制电机(motor)的几个函数

paw.setSpeed(400); //设置转速
paw.rotateTo(nPawHoldPosition); //旋转到一个指定角度(绝对定位)
bottom.rotate(-nFixAngle);    //旋转一定角度(相对定位)

更多的电机相关函数,请点这里看刚刚翻译好的教程。

5,亮度传感器的一个函数,用于把它的灯打开或者关闭。这里是关闭它,省的晃眼睛,需要的时候再开 :)

light.setFloodlight(false);

好了,最终解魔方的动作,都是通过调用这几个函数来完成的。事实上如果你足够无聊的话,现在就可以通过NXT上的几个按键来控制萝卜头玩魔方了。
该吃早饭了,大家自己看看源代码吧。
http://www.diy-robots.com/RubikSolver/SourceCode/NXT/RubikSolverV2.java_20100115.txt

关于机器人小爱,占坑贴

话说萝卜头完工以后,我经常想一个问题:接下来做点啥?

其实这期间有过很多想法,例如乐高打印机,写毛笔字,下五子棋以及等等等等。
面临的问题是,萝卜头就像是家庭的一个成员,实在不忍心拆掉。但是横不能每做一样东西就买一套NXT吧,毕竟咱的钱也不是大风刮来的。

有一天我家娘子说:“我给你出道题吧,给咱们家圈圈做一个小摇篮,如果半夜圈圈哭闹的话,就自动的摇啊摇,这样咱们就不用起来哄了。。”
看,这世界还真是由懒人推动的。我飞快的想了一下,可以用一个亮度传感器判断是白天还是晚上,再用一个声音传感器判断有没有哭闹,最后带动电机来摇动小摇篮,用LabelView就可以实现了。

想到这里,我又回到了那个老问题,有没有必要为这样特定的功能单独用一套NXT,能不能做一个通用的机械结构,既可以下棋,还可以照顾小孩呢?毫无疑问,这就需要一个真正的机器人了。所以我们决定做一个跟大孩子差不多高的小机器人,如果能够制作成功的话,就可以通过软件的更新来实现各种不同的功能。这个小家伙看来是不能用乐高实现了,我准备向那位俄罗斯的手工狂人学习。

这个小家伙的名字叫“小爱”,来源于AI的意思,顺便也沾点爱迪生,爱因斯坦等同学的光。小爱还没诞生,我们就给她安排了很多工作,比如端茶倒水,揉肩捶背,铲冰除雪,溜门撬锁等等(简直就是无良父母啊 :)

YY了半天,赶紧回到现实。我暂时还是电子技术的门外汉,甚至还没有设计过一块电路板。可能有些高手看到这个帖子,会带着鄙夷的酱油飘过“俺们这些专业人士也不见得能做好啊”。嗯,对于困难我早有心理准备,小爱的诞生也许是一个非常漫长的过程,但是年轻啥都不怕,我们都充满信心!

孔子曰:三人行必有我师,n人行必有我n师。希望有更多的朋友光临小站和论坛,分享经验,互相学习,共同进步。

解魔方的机器人攻略17 – 魔方CFOP算法

本来我想把这个攻略做成一个NXT开发的教程,把传感器,电机,发声等部分都介绍一遍。不过现在看来有些同学很心急,希望早点看到“核心代码”,所以我提前把解魔方的算法写出来。其实魔方的算法网上有很多,只要你耐心并且有效的使用搜索引擎,会发现上个世纪就已经有人公布算法或源代码了,例如
算法:http://www.zunny.com/RUBIK.HTM
代码:http://tomas.rokicki.com/cubecontest/

不过我做第一版的时候,还是决定自己动手写算法。原因很简单:我玩魔方很多年了,把玩法转成算法也是我的目标之一。在写程序之前,我画了以下的几张草图:

魔方算法的草稿

魔方算法的草稿

 话说曾经有位同事本打算和我一起做萝卜头的,看了这些草图以后,决定还是继续打游戏更靠谱。这不禁让我想起一首歌“1979年,那是一个春天,有一位老人在中国的南海边画了一个圈…” 这位老同志一定是资深软件架构师,改革开放这么宏伟的事情,画个圈就搞定了。
这样说来我这个草图是太复杂了,难怪把人吓跑了。今天特地又重画了些好看的图,以便大家理解。

魔方表示法
算法的第一个问题就是,怎么用数学方式描述一个魔方状态。我的做法是把魔方想象成一个纸盒子,沿边缝剪开铺平,就形成了六个面,我按照图里的顺序给它们编了号。
每个面又包含了9个颜色小方块,我也按照图中的顺序给它们编了号。

魔方的数组表示法

魔方的数组表示法

这样一来,立体的魔方就变成了一个 6*9 的数组。例如下面是一个普通的被打乱的魔方:

static String SideColors[] = {
  "orgorwwoo",
  "oyggbobrg",
  "yyrgowwbw",
  "yrybgybbo",
  "gwwyybror",
  "bgrwwrbgy"

魔方坐标系:
啥?怎么又有坐标系,刚才的表示法不就完全描述了一个魔方吗?没错,但是咱们的萝卜头每次只能旋转魔方的最下面一层,假设我们需要旋转最上面一层,就必须先把它翻到下面。
请注意在翻跟头的过程中,魔方本身并没有变化,只是坐标系变了。所以还需要一个坐标系来对应萝卜头的空间:

魔方坐标系

魔方坐标系

 

状态变化
正如刚才所说,魔方在萝卜头的数字世界里有两种变化形式:1,翻跟头;2,旋转某一面。
每次状态变化都会造成SideColors数组发生变化,这种转换用最简单的查表法就可以搞定:

坐标变化的大概示意图,坐标变化没啥难度,主要看耐心

坐标变化的大概示意图,坐标变化没啥难度,主要看耐心

例如,这是一段旋转底面后状态转换的代码:

public static void RotateBottomSide(boolean ClockWise) throws Exception
{
 int temp=0;
 int i;

 CopyMatrics(2,6,ClockWise?2:1); //Bottom ClockWise = Top Anti-ClockWise
 CopyMatrics(6,2,0);
 if(ClockWise)
 {
  for(i=0;i<3;i++)
  {
   temp=Sides[5][0][i];
   Sides[5][0][i]=Sides[3][2-i][0];
   Sides[3][2-i][0]=Sides[4][2][2-i];
   Sides[4][2][2-i]=Sides[1][i][2];
   Sides[1][i][2]=temp;
  }
 }
 else
 {
  for(i=0;i<3;i++)
  {
   temp=Sides[5][0][i];
   Sides[5][0][i]=Sides[1][i][2];
   Sides[1][i][2]=Sides[4][2][2-i];
   Sides[4][2][2-i]=Sides[3][2-i][0];
   Sides[3][2-i][0]=temp;
  }
 }
}

CFOP解法
这是由一位叫Jessica Fridrich女士发明的一种速解法,是目前世界上最流行的方块解法。
CROSS:字面上的意思为“十字”,是Fridrich Method中的第一步骤。
F2L:是“First 2 Layer”的缩写,意思为“一、二层”,是Fridrich Method中的第二步骤。
OLL:是“Orientation of Last Layer”的缩写,意思为“最后一层的角块排序”,这是Fridrich Method中的第三个步骤。
PLL:是“Permutation of Last Layer”的缩写,意思为“最后一层的排序”,这是Fridrich Method中的第四步骤。
CFOP:是Fridrich Method的的别称,就是四个步骤“Cross、F2L、OLL、PLL”原文的第一个字母合起来而成的。

上面这些文字比较费解,看下面的图就比较清楚了:

魔方的CFOP入门解法

魔方的CFOP入门解法

或者你可以去魔方小站或者魔方吧看更详细的教程。

CFOP解法的实现
这一部分比较繁琐,输入玩法公式的输入,按照上面的步骤实现以下函数:

TopCross();
TopCorner();
SecondLayer();
BottomCross();
BottomCorner();
ThirdLayerCorner();
ThirdLayerCornerSnap();
ThirdLayerBorderSnap();

CFOP算法的源代码可以点这里下载
通过这个CFOP算法,萝卜头完成了第一版:http://v.youku.com/v_show/id_XNDcwMDQ3NDQ=.html

这个算法的最大问题就是步骤太多,一般来说要120步左右,平均时间12分钟,大多数观众等不到转完就睡着了……
因为这个原因,我改用了一个更快的算法。写博客真是挺累啊,这个算法下次再介绍,心急的同学请看下面这个链接:
http://tomas.rokicki.com/cubecontest/ 点最上面的Winners,我用的是第二名的算法。

解魔方的机器人攻略12 – 安装传感器

这一节要介绍搭建结构的最后一个部分–安装各种传感器。之后我会继续发布软件部分的攻略。
正好今天有位小朋友留言问道,能不能分享源代码。我在这里统一回答一下:在这系列的攻略里,会讲到制作萝卜头所有需要的知识点和注意事项,也会逐步贴出所有源代码。但是在攻略写完之前暂时不会提供下载,因为我希望大家最终自己动手实现,这也正是DIY机器人的乐趣所在!在我制作的过程中,遇到了许多困难,你们已经不需要走太多弯路了(谁敢说我小气,我跟他急^_^)。

引用一段和菜头的话:上网以后,我们把信息当做了知识,把收藏当做了学习,把阅读当做了思考,把储存当做了掌握。像个花栗鼠在秋天收藏坚果一样,把自己的阅读器和硬盘塞满,却依旧觉得饥渴难耐。

言归正传了:

颜色传感器需要的颗粒

颜色传感器需要的颗粒

把颜色传感器安装到电机上

把颜色传感器安装到电机上

非常重要的一步!因为传感器的杆很长,需要一根橡皮筋来避免晃动。

非常重要的一步!因为传感器的杆很长,需要一根橡皮筋来避免晃动。知足吧,这一根皮筋是我被折磨了一星期之后才想到的...

 

超声波测距传感器

超声波测距传感器

安装在最高点,它的作用是判断转台上有没有魔方

安装在最高点,它的作用是判断转台上有没有魔方

亮度传感器

亮度传感器

组装成一个奇怪的样子

组装成一个奇怪的样子

安装的目标是这里

安装的目标是这里

安装之后的效果,注意看上面的底盘,贴了一圈白纸,原因在软件部分会介绍

安装之后的效果,注意看上面的底盘,贴了一圈白纸,原因在软件部分会介绍

距离上需要留一个2到3毫米的间隙

距离上需要留一个2到3毫米的间隙

固定NXT主体

固定NXT主体

从另一个角度看看怎么固定

从另一个角度看看怎么固定

最后的一些工作:接线,贴提示的彩条,把剩余的散件用来加固,还有就是化化妆

最后的一些工作:接线,贴提示的彩条,把剩余的散件用来加固,还有就是化化妆

接线方式说明:

电机A:爪子
电机B:魔方的旋转底盘
电机C:颜色传感器电机

传感器1:超声波测距传感器
传感器2:亮度传感器
传感器3:颜色传感器
传感器4:按钮(这个是我调试的时候用来中断的)

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

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

一大堆散件

一大堆散件

组装起来

组装起来

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

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

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

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

组装好的连杆

组装好的连杆

与悬臂的连接

与悬臂的连接

大体框架已经搭成了!

大体框架已经搭成了!

加个小人点缀一下

加个小人点缀一下

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

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

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

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

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

准备一个电机

准备一个电机

连接电机轴,引出动力

连接电机轴,引出动力

几个连接件

几个连接件

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

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

这是下面的支架

这是下面的支架

和大底盘的对接过程

和大底盘的对接过程

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

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

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

这是两个悬臂

连杆的安装位置

两个悬臂的安装位置

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

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

安装完成了

安装完成了

绕到后面看一眼

绕到后面看一眼

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

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

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

换个角度来个特写

换个角度来个特写

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

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

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

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

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

下面进入正题:

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

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

准备好电机和一些连接件

准备好电机和一些连接件

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

插上以后的效果

插上以后的效果

电机连接需要的配件

电机连接需要的配件

电机连接效果

电机连接效果

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

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

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

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

支架需要的配件

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

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

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

支架和电机连接

支架和电机连接

加一个蓝色插销加强一下

加一个蓝色插销加强一下

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

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

准备做另一边的支架

准备做另一边的支架

组装后的第二个支架

组装后的第二个支架

支架与电机连接

支架与电机连接

这些是固定宽度的撑杆

这些是固定宽度的撑杆

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

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

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

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

解魔方的机器人攻略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公里,就可以获得几百大洋的奖金。
有一位年轻人恰好出差到此,跑两小时就有几百大洋入账,不赚白不赚啊!
不幸的事情发生了,半路上他亲眼目睹了一个同事倒下,心脏病突发。
虽然这种事在长跑中很常见,虽然和这位同事素不相识,但是年轻人还是被震撼了
人生如白驹过隙,你曾经想过要做一些事情,但是“有空了再说吧”,“有钱了再说吧”。。懒人的借口总是好找的。
当然,大多数人不会以这种突然的方式离去,他们只是在不知不觉中变老,然后有一天,他们会“突然”发现自己没多少时间了。
所以他决定做点事情,从十多年前被鄙视的小心愿开始做起。
题外话:世事就像变幻莫测的魔方,一串貌似毫不相关的因,可能会结出一个莫名其妙的果。这就是传说中的蝴蝶效应吧!