Posts Tagged ‘机器人’

PR2机器人 – 穿袜子

一直很关注Willow Garage的PR2机器人,我想象中的小爱就应该是这个样子。这个家伙是加州大学伯克利分校的机器人实验室开发制作的,可以打台球,送饮料,叠毛巾等等。据说是个开源项目,目前已经公布了部分软件代码,结构和硬件设计没有公布。当然这种东西即使公布了,也不是普通人玩的起的。我等业余爱好者,做一个能走能动的小爱就可以偷笑了。贴几张照片,做的非常精致:

效果图

效果图

 

抓杯子和倒水

抓杯子和倒水

 

爪子

爪子

 

手臂

手臂

 

实验室

实验室

 

自己找插座充电
自己找插座充电

今天早上在煎蛋看到PR2穿袜子的视频,动作那是相当的……猥琐!没错,就是猥琐,忍不住转载供大家娱乐一下。

 

解魔方的机器人攻略28 – 总结

经过这么长的时间,终于把萝卜头的制作攻略全部发完了。这次发攻略的过程,我把萝卜头重新搭建了一遍,把所有的代码也整理重写了。新版的小萝卜头看上去更好看一点(个人感觉,呵呵),代码容错能力也强了很多。现在在各种不同的灯光条件下,基本都可以正确识别颜色,并且转动过程中,魔方掉下来的情况也很少见了。终于松了一口气,对博客和对萝卜头都算有一个交代了。

我家圈圈很快就要降生,接下来的一段时间博客可能会很少更新。小爱的进度看来已经远远落后,目前还只是一个可以用手机遥控的小车。不过来日方长,我会继续制作并且和大家分享的。

NXT端的程序下载(源代码)

PC端的程序下载(exe)

下面转几个国外达人制作的魔方机器人,其中最快的已经可以在十秒左右解出魔方。据说人类的世界记录是7秒多,有志于突破人类极限的朋友,可以参考参考,我非常愿意为此贡献一点力量。

世界最快的乐高魔方机器人

目前最快的魔方机器人

目前最快的魔方机器人

作者把视频发在了youtube上,无法转载,有兴趣的同学请自行翻墙过去看看:
http://www.youtube.com/user/RoboticSolutions
介绍文章:
http://singularityhub.com/2010/02/17/lego-robot-solves-any-rubiks-cube-in-less-than-12-seconds-video/

五阶魔方机器人
用的也是Lego studio摄像头+NXT,5阶魔方还原算法自然是这个机器人的核心,但并非lego范畴,这里可以看到David Gilday愈加成熟的PC端处理程序,看起来相当酷。此外玩过多阶魔方的朋友都知道,这种魔方的翻转定位是最大的问题,所以这款机器人采用了一个相对丑陋的框式造型来帮助解决这个问题,气势上差了一点,但毕竟是第一款,6分43秒185步的测试水平也算世界纪录了。

视频地址

URL:
http://www.tudou.com/programs/view/HXeCwaDdXW0/

大型魔方机器人
大型机械臂,从取魔方,识别,到翻转,放回,仿佛可以看见不远将来家里的小机器人接过你随手拧乱的魔方,咻咻复原的可爱场景。
视频地址:

URL:
http://www.tudou.com/programs/view/TLuTp8mWLPM/

四阶魔方机器人
这是一款用NXT+N95手机的魔方机器人,旋转的结构很酷:
http://blog.izxg.com/?tag=%E4%B9%90%E9%AB%98

解魔方的机器人攻略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,暂停功能,帮助我们进行调试

解魔方的机器人攻略23 – 识别颜色(上)

今天看到架子上的萝卜头,已经落了很多灰尘。想起萝卜头的攻略还剩几篇迟迟没有写完。前一段时间一直在试验小爱的手机遥控器功能,从今天开始准备陆续把萝卜头的攻略补完,给博客也打扫打扫灰尘。

说起来真是很惭愧,颜色识别在萝卜头制作过程中是花费时间最多的部分。其中还有一段小插曲:
我在淘宝上买的颜色传感器,在NXT上测试时,发现只有用强光照射在魔方表面的时候,传感器才有读数。那时候在网上很难找到相关的资料,不知道是我买了次品,还是设置不当。后来我猜想传感器中心的那个透明小灯泡是光源,就擅自去电子市场买了一个LED小灯,然后把这个500块钱的传感器敲开换上。一通电,嘿,灯居然亮了,然后我就把拆下来的小灯扔到垃圾桶继续测试。结果…..这次传感器彻底废了。接下来是从垃圾桶里翻那个透明的小灯泡,非常悲剧的是那天正好吃了虾和鱼,我把整垃圾桶的虾皮鱼骨摸了两遍,才找到那个透明的小灯泡,把它洗洗干净又换上了。后来才知道,这个灯泡其实是用来读取颜色的,而不是照明的。而我买的那个颜色传感器确实是个次品,必须用灯光照射才能勉强读数。所以你们看到第一版的萝卜头,在悬臂上是带有一个照明灯的。

在此提醒一下朋友们:颜色传感器在普通的光照环境下,应该是有读数的,而且很敏感,读数会不断小幅跳动。如果你买的传感器读数一直是0或者跳动非常大,那么请尽快找奸商退换。另外,在这里感谢一下北京西觅亚公司,他们给我提供了几个测试用的颜色传感器,并且给我换了一个新的。我也因此了解了一些颜色传感器的特性。

好了,进入正题。上一篇介绍了如何在电脑和NXT之间使用蓝牙进行通讯。有了蓝牙,我们就可以把颜色传感器的读数发送给电脑,然后用电脑识别颜色后调用解魔方的算法。

1,从NXT发送颜色数据到电脑
之前的一篇博客里,我介绍了三个函数:ReadAllSide,ReadOneSide和SendColorToPC。现在蓝牙已经调通,可以改写SendColorToPC函数用来发送数据。其中getRed()和getRawRed()等函数的说明,请参考颜色传感器的API文档

//Send colors to PC
public static void SendColorToPC(int center, int n) throws Exception
{
	//get the x,y of n
	int y = n % 3;
	int x = (n - y) / 3;

	//send to PC by bluetooth
	byte[] data = new byte[9];
	data[0] = (byte)center;    //center表示是魔方的某一面
	data[1] = (byte)x;         //x 表示魔方这一面3*3的色块中,第x行的色块
	data[2] = (byte)y;         //y 表示魔方这一面3*3的色块中,第y列的色块
	data[3] = (byte)color.getRed();
	data[4] = (byte)color.getGreen();
	data[5] = (byte)color.getBlue();
	data[6] = (byte)(color.getRawRed() / 3);
	data[7] = (byte)(color.getRawGreen() / 3);
	data[8] = (byte)(color.getRawBlue() / 3);
	BlueTooth.WriteBytes(data);
}

2,在PC端接受颜色数据
PC程序中的BlueToothDataReceived函数,用来响应接受到蓝牙数据的事件。我们加上下面这段函数:

else if (length == 9)
{
    int i = data[0];
    int j = data[1];
    int k = data[2];
    int r = data[3];
    int g = data[4];
    int b = data[5];
    int rawR = data[6];
    int rawG = data[7];
    int rawB = data[8];
    ColorItem newItem = new ColorItem(i, j, k, r, g, b, rawR, rawG, rawB);
    colorDistinguish.ColorItems.Add(newItem);
    DisplayMessage += newItem.ToString() + "\r\n";
    Status = "成功获取数据:" + i + "," + j + "," + k;
}

其中用到了两个类 ColorItem 和 ColorItemDistinguish。这两个类的作用后面再说,总之这里把所有的颜色数据都先保存到一个阵列(Array)里,最后统一识别颜色。

3,解析颜色的方案
细心的朋友可能在API中看到了getColor()函数,我们何必要全部保存颜色后再统一分辨呢,直接读一个分辨一个不是更好?事实证明这个函数基本没什么用,红色和橙色都会解析成红色,而且环境光线变化时影响很大。还有一些朋友建议用HSV颜色模型,这种方案我也试过了,基本上也很难分辨。为什么呢?请看下面一组读数:

Red
[0,1,2]=>RGB=(23,0,0),RawRGB={45,1,8}
[0,2,2]=>RGB=(30,0,0),RawRGB={60,1,5}
[0,2,1]=>RGB=(25,0,0),RawRGB={49,3,12}
[0,2,0]=>RGB=(32,0,0),RawRGB={63,2,6}
[0,1,0]=>RGB=(22,0,0),RawRGB={43,2,11}
[0,0,0]=>RGB=(25,0,0),RawRGB={59,3,3}
[0,0,1]=>RGB=(30,0,0),RawRGB={58,5,17}
[0,0,2]=>RGB=(31,0,0),RawRGB={61,8,17}
[0,1,1]=>RGB=(31,0,0),RawRGB={62,15,22}

Orange
[2,1,2]=>RGB=(28,0,0),RawRGB={55,12,8}
[2,2,1]=>RGB=(30,0,0),RawRGB={57,14,14}
[2,0,1]=>RGB=(32,0,0),RawRGB={62,15,13}
[2,1,0]=>RGB=(32,0,0),RawRGB={63,16,12}
[2,2,2]=>RGB=(42,0,0),RawRGB={83,24,10}
[2,2,0]=>RGB=(41,0,0),RawRGB={82,24,13}
[2,0,0]=>RGB=(41,0,0),RawRGB={80,23,10}
[2,0,2]=>RGB=(39,0,0),RawRGB={76,22,13}
[2,1,1]=>RGB=(41,5,0),RawRGB={81,30,21}

这是在自然光条件下,对红色和橙色的9个色块分别读数的结果。可以看到,它们的Green和Blue分量全部是0,只有红色分量有差别。但是红色的red分量从23~32,橙色的red分量从28~42,它们中间是有重叠的。对于这些读数,HSV完全没用。
有一段时期我几乎已经绝望了,不过终于在最后让我找到了一点区别:红色的RawBlue分量基本上比RawGreen分量稍大,而橙色恰好相反。另外请对比一下[0,0,0]和[2,2,1],它们的RawBlue分量和RawGreen分量是相同的,但是仍然可以找到区别:按公式R+2*RawG-2*RawB计算,橙色的永远比红色大!

也就是说,我们单独取到一组颜色数值时,很难直接知道它是什么颜色,只有对一组数进行排序后,才能区分出不同的颜色。就像刚才这18个数,我们按照R+2*RawG-2*RawB从大到小排序,最终结果的前9个是橙色,后9个就是红色。类似的,我们还可以定义出分辨颜色的判断规则:
1,假设RGB三个值的最小值为Min,按Min从大到小排序,前9个是白色
2,剩下的颜色,按照G分量从大到小排序,前9个是黄色(有意思吧,绿色分量最大的是黄色)
3,剩下的颜色,按照B分量从大到小排序,前9个是蓝色(这个还算靠谱)
4,剩下的颜色,按照R分量从小到大排序,前9个是绿色
5,剩下的颜色,按照R+2*RawG-2*RawB从大到小排序,前9个是橙色
6,剩下的颜色全是红色

当光线从弱到强变化时,这些值基本会成比例的变大,所以这些规则依然有效。
有兴趣的朋友可以查看一组完整的颜色读数,来验证以上这些规则:http://www.diy-robots.com/rubiksolver/readcolors.txt
下一篇继续介绍这种分辨方式的具体代码实现。

底盘小车 – 框架

春节期间给小爱做了一个测试版的底盘小车,这两周工作太忙,没有什么进展。今天先补上记录。

话说上个月有个网友,问能不能参观一下我的工作室。其实我是一个标准IT宅男,俗称闭家锁,一般不参加网友活动,更别说请人回家参观了。不过我在网上就非常好客,比如可以参观一下我的豪华工作台:

打孔的地方

打孔的地方

下面那个脏兮兮的玻璃台子曾经是个鱼缸,小金鱼们已经被放生到昆玉河,目前下落不明。观察力敏锐的同学会发现工作环境光线很好。没错,其实我的工作室不仅光线好,还视野宽阔,空气清新,唯一的缺点是冬天有点冷:

工作室就是我家的阳台

工作室就是我家的阳台

不说废话了,首先看看之前做好的轮子,预留了一个方便安装的直线轴承。

轮子和轴承

轮子和轴承

量好尺寸,根据小爱将来的宽度做一点计算,然后用铅笔在铝条上划线。

划线

划线

现在需要在铝条上折出两个直角。没想到3mm厚的铝条居然这么硬,如果直接用钳子掰的话,只能弯成一个大圆弧形。不过不要紧,工程师是不会被工具难倒的。想起之前拆的那个鞋架子。用两个木条做成夹棍,把铝条用螺丝固定在中间,最后垫在那块万能菜板上使劲敲,这样就弯出了比较完美的直角:

木条制作的“老虎钳”

木条制作的“老虎钳”

接下来就是在我的豪华工作台上打孔了。那个手持的小电钻真是不太好用,钻头晃的很厉害。这里给大家介绍一个小经验,用钉子在划线的地方敲一个小坑,然后用钻头顶住小坑再开始打孔,这样位置就精确了,而且打孔速度会快很多。看看打好孔的铝条:

打孔后的铝条

打孔后的铝条

临时装上轮子看看装配的尺寸是否合适

检查打孔的尺寸

检查打孔的尺寸

好了,既然尺寸还凑合,拆下轮子继续划线打孔,把整个底盘的架子装好。

底盘架子

底盘架子

接下来是安装轮子和直流电机:

轮子和直流电机

轮子和直流电机

驱动小车用两个直流电机就够了,另外一端使用的是两个万向轮:

万向轮

万向轮

最终的成果是这样的:

大功告成

大功告成

这个小车做好以后,我把Arduino实验板,直流电机控制板,电源,笔记本都架在小车上做了一个实验。可以顺利完成前进后退和转弯的动作。不过电机控制使用的是笔记本+USB线,所以暂时还不能实现遥控。这几天正在试验把我的手机作成遥控器,如果能搞定的话发上来跟大家分享。另外萝卜头的攻略还差几篇,接下来这段时间争取把它们写完。

工具啊工具

今天早上一直在露台上锯东西,下午右肩膀开始酸痛,晚上已经疼到举不动东西,估计接下来的几天要歇着了。据老丈人说,我那个锯弓不稳,锯条齿太细,所以锯起来太累。下回送我什锦锉的时候,顺便再送我几根粗牙锯条。

这几天北京大风降温,我在露台上叮叮咣咣的干了几天活,冻了个半死。便携式的电钻真是不够结实,打十几个孔以后钻头就开始打滑;砂轮也是,磨一根45#钢的轴,能把砂轮片打掉一半。这要是在工厂,连磨带钻也就是一两个小时的时间。

果然是“工欲善其事,必先利其器”。过段时间准备买一个小型台钻,这样打孔能方便点。如果有北京的朋友可以联系到加工厂或者车间,能够方便实惠的加工点东西,希望给我介绍一下。多谢了!

春节快过完了,休息几天就得收心回去上班了。发一张目前进度的照片吧,过几天再发详细点的攻略。

有点雏形的小车底盘

有点雏形的小车底盘

底盘小车的制作 – 轮子

春节期间老丈人和丈母娘来北京了。本来我还非常担心,如果老人们发现我每天捣腾这些东西,一方面可能觉得我不务正业,一方面也可能会觉得自己的闺女生活在水深火热之中。

老丈人曾经做过十多年的铣工,知道我这点小爱好以后,非常有兴趣,这几天一直跟我一起探讨和制作机械部分,还说回家以后要送我一套什锦锉。哈哈,也许男人就是天生的机器人爱好者 :D
废话不多说了,先看看最近几天的进展。

首先是订制的几根45#钢的小轴,春节前终于送到了。下面是我手绘的加工图和送到的小轴:

小车的轴

小车的轴

非常杯具的事情:我只标注了Φ8的直径,没有标注公差,所以寄来的小轴比轴承粗了0.2毫米。用磨刀石磨了半天,发现45#钢真是太硬了,这样下去胳膊磨细了轴也细不了。用砂轮打的话,又担心打不圆。经过和老丈人的讨论,决定制作一个小型“车床”,用来打磨这根轴。正好可以用小车的电机来驱动。这是从百宝箱里搜刮出来的各种杂物:

各种车床配件

各种车床配件

家里最可怜的菜板,一直被我用来做各种实验,这次它会变成一个车床。

百变菜板

百变菜板

直流电机需要一块角铁做支架,百宝箱里找不到合适的配件,我在家里寻摸了半天,终于发现电脑桌下面有几块合适的角铁,趁着老婆去午睡的机会把它拆了。作为补偿,让电脑桌也上个镜头:

电脑桌下面的角铁

电脑桌下面的角铁

看,和直流电机简直就是天生的一对

直流电机的支架

直流电机的支架

再用一块不知道从那里捡来的T型铁皮做成支架,一个简易的小车床就制作完成了:

小型车床

小型车床

接下来就是用砂轮打磨了,老丈人亲自操刀上阵,看看战斗现场:

打磨短轴

打磨短轴

经过打磨的短轴终于可以安装到轴承里了,事先套上一个直线轴承,然后装上传说中的无敌风火轮:

安装轮子

安装轮子

在轮子的另一面,用一个锥型齿轮,把动配合变成静配合,再用螺丝拧紧固定:

锥齿轮固定

锥齿轮固定

最后把打磨用的直流电机拆下来,用联轴器连上。把上面的工序一式两份,底盘小车的两个驱动轮就完成了。明天的计划用铝条和角铝把两个轮子连上,然后再添加两个万向轮制作成底盘。两个直流电机的功率还没有试过,希望能带的动二十公斤的重量。

做好的轮子

做好的轮子

疯狂大采购

最近一直没上来发攻略,主要的时间都在淘宝上逛街了。现在的小爱已经有一个大概的框架图,具体的搭建还需要不断的买材料,调整,再买材料,再调整。

发一些最近买的东西,留个纪念:

无敌风火轮,这是滑板车的轮子,准备做小爱的驱动轮

无敌风火轮,这是滑板车的轮子,准备做小爱的驱动轮

这是万向轮,一般用来做柜子,这个准备做小爱的辅助转向轮

这是万向轮,一般用来做柜子,这个准备做小爱的辅助转向轮

这个是锥齿轮,可以用于轴的转向,其实这是麻将桌的配件,每个5毛钱

这个是锥齿轮,可以用于轴的转向,其实这是麻将桌的配件,每个5毛钱

五金店买的一些金属材料,还没想好怎么用

五金店买的一些金属材料,还没想好怎么用

另外一些舵机专用的支架,和上一个图有些重复

另外一些舵机专用的支架,和上一个图有些重复

各种电机和舵机,一共十多个,刚拆包了几个做了测试

各种电机和舵机,一共十多个,刚拆包了几个做了测试

各种轴承

各种轴承

无数默默无闻的螺丝钉

无数默默无闻的螺丝钉

另外还有一些开发板和传感器还没拍照,等下回做实验的时候发。希望明天几根定制的轴能送到,周末就可以组装点东西了。

解魔方的机器人攻略21 – 读取魔方颜色

之前已经介绍了萝卜头转魔方的各个分解动作,今天介绍如何用颜色传感器读取魔方的颜色。这一部分可以分成三部曲:
1,依次扫描魔方的6*9=54个色块
2,用蓝牙连接把数据发送到电脑
3,通过颜色分组函数,从读数分辨出不同的颜色

这里先说明一下:虽然乐高的颜色传感器以RGB的形式返回颜色值,但是并不是想象中的那样,红色返回(255,0,0),蓝色(0,0,255)这么轻松。事实上这个数值受环境光线强度影响非常大,即使相同的环境下,读数仍然会有跳动。例如下面几个读数:

[0,1,2]=>RGB=(23,0,0),RawRGB={45,1,8}  //红色
[0,2,2]=>RGB=(30,0,0),RawRGB={60,1,5}  //红色
[2,1,2]=>RGB=(28,0,0),RawRGB={55,12,8}  //橙色
[2,2,1]=>RGB=(29,0,0),RawRGB={57,14,14}  //橙色

如果你仅想从RGB来分辨颜色的话,将会“很受伤”。不过今天我只介绍第一步(扫描),在PC端程序部分再介绍如何识别颜色。

因为颜色传感器一次只能读一个点,所以要扫描魔方的话,必须把54个点都扫到。我们以扫描其中一个面为例,看看两个电机怎么配合扫描到所有的9个点。首先,颜色传感器的电机中心位置,应该在2,4两个点的中心延长线上。这样在魔方位置不动的情况下,就可以扫描到中心和四个角了。(相关文章:颜色传感器的安装

扫描魔方中心和魔方的角

扫描魔方中心和魔方的角

然后,让底座旋转一定的角度,同时传感器电机也稍微调整,这样就可以扫到4个棱的颜色。

扫描魔方的棱

扫描魔方的棱

以这种方式扫描一圈,就可以把魔方的一个面读完了。最后使用魔方操作的分解动作,把魔方翻过来倒过去,直到把六个面依次扫描出来。有一件非常麻烦的事情是,在魔方翻来翻去的过程中,数组并不是每次都以0为左上角,它是不停的变换的(相关文章:魔方坐标系)。我用了下面这个map表,用来标记读数的顺序,这可是牺牲了数百个脑细胞换来的,其中idx数组是每个面内的依次读取顺序,idex2数组是不同的面的读取顺序:

int[][] idx={
	{4,6,7,8,5,2,1,0,3},
	{4,0,3,6,7,8,5,2,1},
	{4,2,1,0,3,6,7,8,5},
	{4,8,5,2,1,0,3,6,7},
	{4,2,1,0,3,6,7,8,5},
	{4,2,1,0,3,6,7,8,5}};
int[] idx2={5,1,4,3,2,0};

我们以上一次的程序为基础,添加以下变量和函数:

	//add offset positions for color sensor motor
	static int ColorMotorOffset1 = 33;
	static int ColorMotorOffset2 = 9;
	static int ColorMotorOffset3 = 18;
	static int ColorReadPostion1 = 162;
	static int ColorReadPostion2 = 154;

	//Read each side colors of the cube
	public static void ReadAllSide()
	{ }

	//Read one side by the index
	public static void ReadOneSide(int nSideIndex)
	{ }

最后加一个测试入口,当按下Enter键时,开始扫描魔方。相信看过前面文章的朋友,这里不需要说明了。点此查看具体的代码吧。

补充个小小的说明:我在代码里面统一用英文加了注释,不是在装酷,主要是因为上班的时候是这样强制要求的,以至于自己做东西也养成这种习惯了。

机械结构 – 一次不成功的尝试

据说DIY机器人最麻烦的步骤就是加工零件,主要是因为加工设备太少,巧妇难为无米之炊嘛。我买了一本叫《机器人制作入门篇》的书,作者的家里居然有小型车床和铣床。可是北京的房价这么贵,人都不够住,哪有地方放这么多东西。

前几天我突发奇想,打算试试用废旧的玩具和家具来加工“零件”,因为木头比金属还是容易处理一点,用牙都能啃个豁口出来。所以有了下面的一个小尝试,这次尝试的目标是做一个小车底座。

当然,大家看了标题,已经知道这是一个不成功的案例了。其实我本来想把标题写成“一次失败的….”。后来想起一句老话:没有所谓失败,因为至少排除了一种不可行的方案。正好快过年了,把不开心的事情说出来,让大家开心一下。

首先,盘点一下手头的家伙,看上去还真不少:

家里的工具们

家里的工具们

接下来的工作是忽悠老婆,就说家里的鞋架子已经臭了,该换一个了,然后把它拆成了无数的木条。下面是用小刀抠出来的轴承座:

用小刀抠的轴承座

用小刀抠的轴承座

剪一块罐头铁皮,用钉子在两头打眼,把轴承固定在木头上:

做好的轴承

做好的轴承

一式两份:

两个轴承座

两个轴承座

下面这个是用膨胀螺栓掰成的“联轴器”,外加铁棍和玩具车的轮子:

轮子和轴

轮子和轴

可以变方向的另外两个轮子,木头上的那两个窟窿,废了半天劲用磨轮打出来的:

另外两个轮子

另外两个轮子

用来调节宽度的两个小木块,调节方法是:如果宽了一点,就用小刀把它削平。

宽度调节“装置”

宽度调节“装置”

最后的组装:

小车底座的最终结果

小车底座的最终结果

做到这里就结束了,本来应该还有几个步骤。应该把长出来的轴锯掉,然后接上电机,后面的两个轮也要加上一个控制方向的电机,就变成了一个小车底座。

没有做下去的原因包括:
1,木头+山寨工具=误差,精度实在很差,强度也不够
2,污染很大,满屋子一股奇怪的木头味,另外还有噪声污染
3,粗大的件可以做,复杂的小件做不了

考虑到家里还有孕妇,实在是不能再这么玩了。难怪老外们一说起创业,就是在车库里面,那是一个可以随意折腾的地方。接下来还是打算画点AutoCAD的图,送去工厂加工,不知道要花多少银子啊 :)

最后附上工作照一张,颇有恐怖分子的气质:

工作照

工作照