2010年03月 文档列表

蓝牙手机变身小车遥控器 (3)

发现已经一星期没有更新博客了,真是非常抱歉。上周做完手机遥控器以后,一直没有其他进展,也没来得及发攻略。接下来的时间可能会更忙,只能先跟大家说声抱歉了。在此严重羡慕一下大苹果同学,这个家伙周末带mm飞去武汉大学看樱花了,眼红啊。。。

今天跟大家分享一下在Windows Mobile环境里,如何配置和调用Web Service(就是上次说的四个程序中的第二个)。

一、首先配置开发环境,需要安装下面的几个东东:
1,VS2008 及其 SP1
2,Windows Mobile 6 Professional SDK Refresh.msi
3,Windows Mobile 6.5 Professional Developer Tool Kit (CHS).msi

安装之后,在“新建工程”菜单里,就可以看到智能手机的选项:

新建智能手机项目

新建智能手机项目

新建智能手机项目只有一个选项,输入项目名称后,单击进入下一步,选择平台版本:

选择手机版本

选择手机版本

单击确定,一个新的手机项目就建好了。

新建的工程

新建的工程

二、控件,编译和部署
试着拖两个按钮到手机界面上去,你可以发现跟普通的windows应用程序开发是类似的。我添加了三个按钮,分别是“启动”,“停止”和“退出”。双击“退出”按钮,对按钮添加相应的事件,其他两个按钮稍后再说:

private void ExitButton_Click(object sender, EventArgs e)
{
    this.Dispose();
    this.Close();
}

选择菜单中的“编译->编译项目”,然后到这个项目的文件夹目录里面翻一翻,在 \PhoneRemoteControl\bin\Debug目录下,可以发现多了个exe文件。

先别激动,这个文件在电脑上双击是不能运行的。必须要复制到手机上,用你的手指头单击它,然后发现……还是不能运行。

嗯,这是因为你的人品不够好,弥补办法是去微软网站上下载一个叫“NET Compact Framework”的东西并安装上。

好了,再用一阳指点一下,这次可以看到软件的界面了,再点一下“退出”按钮,程序就退出了(好像是废话)

三、调用Web Service
首先要在工程中引用WebService:在工程名字上用右键,弹出的菜单中选择“add web reference”。我这个是英文版,不知道中文版里叫什么,参考一下吧:

add reference

add reference

在接下来的设置窗口里,输入上一步中做好的web service地址,另外给它起个名字叫“PingService”:

输入service地址

输入service地址

添加了service之后,咱们看看怎么调用,非常简单,用一个函数就可以了:

private void WCFRequestCall(string data)
{
    PingService.Ping client = new PhoneRemoteControl.PingService.Ping();
    client.Url = "http://chenwu03/service/ping.asmx";
    client.SetData(data);
}

这里有一句 client.Url=”…”; 这个为部署修改用的,例如你开发的时候用chenwu03,将来可能换到另一台电脑上,那么在这里改成chenwu04就可以了。建议把这个参数放到配置文件里,这样如果需要修改的话,不需要改代码重新编译,直接用写字板改一下配置文件即可。

四、在手机上画方向盘
其实想要遥控小车,用前进后退,左转右转几个按钮就可以了。但是为了捍卫Dev的尊严,我决定做的花哨一点,于是很骚包的画了一个方向盘。在Form中绘图,可以在一个叫Form1_Paint的函数中添加程序,不说废话,看代码吧:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    int windowWidth = 480;
    int borderOffset = 40;
    int topStart = 160;
    int lineOffset = 25;
    int r = windowWidth / 2 - borderOffset;

    Graphics g = this.CreateGraphics();

    Pen pen = new Pen(Color.Red);
    pen.Width = 3;
    pen.DashStyle = DashStyle.Dash;
    g.DrawLine(pen, borderOffset-lineOffset, topStart + r, windowWidth - borderOffset+lineOffset, topStart + r);
    g.DrawLine(pen, windowWidth / 2, topStart - lineOffset, windowWidth / 2, topStart + 2 * r + lineOffset);

    pen.Color = Color.Blue;
    pen.DashStyle = DashStyle.Solid;
    pen.Width = 8;
    g.DrawEllipse(pen, borderOffset, topStart, 2 * r, 2 * r);

    steeringWheel.CenterX = windowWidth / 2;
    steeringWheel.CenterY = topStart + r;
    steeringWheel.R = r;
}

画出来的效果如下:

在手机上的效果

在手机上的效果

五,计算小车的速度
因为Arduino中,直流电机的控制是通过PWM管脚输出的,值范围是0~1023;所以我让手机发出的数据就是简单的“VLeft,VRight”,值的范围都是从0到1023,用正负号表示前进还是后退。

设计的思路是,点击圆圈的正上方时,两个轮子都向前走,离圆心越近速度越慢,最远的地方发送的数据是“1023,1023”;
类似的,点击最下面时,发送的数据是“-1023,-1023”;
当点击圆圈的左边时,我会把右侧的速度变大,左侧的速度变小,这样小车就向左转了;
当点击到圆圈外面时,直接忽略掉。

需要注意的是,在实际操作中,当输出速度低于300时,电机其实已经带不动了,所以我把低于300的值全都重置成0。这部分代码就不贴了,反正大家可以按照自己的喜好编写控制代码。需要的同学可以下载代码回去参考下。
至于上面提到的“启动”和“停止”按钮,我们就发送“600,600”,“0,0”两组数据即可

六、发送数据
当你的咸猪手在手机上乱摸时,我是用Form1_MouseMove来响应事件的。事实证明,这个数据发送的频率太高了,每秒钟会发送几百组速度。为了回避这个问题,我们设置一个定时器,每隔150毫秒执行一次,中间MouseMove的事件全部扔掉。

private string currentCommand = "";
private string lastCommand = "";

private void SendTimer_Tick(object sender, EventArgs e)
{
    if (!string.IsNullOrEmpty(lastCommand))
    {
        currentCommand = lastCommand;
        lastCommand = "";
    }
    if (!string.IsNullOrEmpty(currentCommand))
    {
        WCFRequestCall(currentCommand);
        currentCommand = "";
    }
}

好了,接下来是检查工作成果。用手指头在屏幕上一阵乱摸,可以从端口监视器里看到不断跳出来的数组:

端口监视器

端口监视器

有经验的同学可能有两个问题:
1,为什么不直接用WebRequest发起请求呢?
这个我试过,手机容易死机,原因还不清楚
2,为什么不直接用TCP/IP发送数据到PC端口呢,绕这么大一圈?
这个我也试过,程序不会出错,但是电脑上也没有接到数据,原因依然不清楚

不管怎么说,反正试出来一个可行的方法。这篇博客中提到的源代码在这里下载,其他部分下回继续:
http://www.diy-robots.com/Resources/XiaoI/PhoneRemoteControl.zip

蓝牙手机变身小车遥控器 (2)

过生日这几天一直在腐败,今天抽时间把小车遥控器的攻略补上。这个小车遥控器一共需要四个程序,首先看看运行在笔记本上,用来接收手机指令的Web Service。

先创建一个Web Service工程,命名为 WCF_ReceivePhoneMessage:

创建 WebService 工程

创建 WebService 工程

在工程根目录里新建一个文件Web.config,并添加以下的设置:

  <appSettings>
    <add key="PortNumber" value="31718" />
  </appSettings>

这个是将来用来转发指令的Socket端口号。接下来再创建一个ping.asmx文件,这个就是传说中的Web Service的接口,代码如下:

	[WebService(Namespace = "http://www.diy-robots.com/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class Ping : System.Web.Services.WebService
    {
        static private int PortNumber = Convert.ToInt32(ConfigurationManager.AppSettings["PortNumber"]);

        [WebMethod]
        public void SetData(string data)
        {
            if (!string.IsNullOrEmpty(data))
            {
                try
                {
					//Here are codes to get the IP address of local computer
					//You can also set it directly
                    string ipAddress = "";
                    IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
                    foreach (IPAddress ipAddr in ipHost.AddressList)
                    {
                        ipAddress = ipAddr.ToString();
                        if (ipAddress.IndexOf(":") < 0) break;
                    }

					//Send TCP/IP data
                    TcpClient client = new TcpClient();
                    client.Connect(ipAddress, PortNumber);
                    NetworkStream stream = client.GetStream();
                    byte[] bytes = Encoding.ASCII.GetBytes(data);
                    lock (stream)
                    {
                        stream.Write(bytes, 0, bytes.Length);
                    }
                    client.Close();
                }
                catch (Exception) { }
            }
        }
    }

段代码其实很简单,就是创建一个SetData函数,把传进来的string类型的参数转成byte数组,然后转发到制定的Socket端口。为了让这个Web Service生效,还需要在IIS里面生成一个应用程序。看下面这个图:

设置IIS

设置IIS

IIS设置设置好了,咱们在浏览器里简单测试一下程序是不是部署成功,输入下面的地址:其中ComputerNames是你自己电脑的名字
http://ComputerName/service/ping.asmx?op=SetData

这个页面只要不出错就算成功了,正确的显示应该是这样:

Web Service创建成功

Web Service创建成功

本来想把手机上的程序也一起发完,不过又累又困,下回再说吧 :)

上面这个web service的源代码可以在这里下载:
http://www.diy-robots.com/Resources/XiaoI/WCF_ReceivePhoneMessage.zip

大雪纷飞的31岁生日

31岁了!今天真是个好日子,北京下了入冬以来的第十场雪。

今天是圆周率日,google发来贺电:

圆周率日

圆周率日

今天也是白色情人节,微软发来贺电:

白色情人节

白色情人节

今天是爱因斯坦诞辰131周年,不过他是前辈,没有发来贺电。

最后贴两张玉皇大帝送的生日礼物:

北京的雪

北京的雪

北京的雪

北京的雪

复杂和简单

在家里,老婆的智商一直是我的嘲笑对象。我有一个大抽屉,里面有各种奖状,例如竞赛,奖学金,三好学生,金质奖章等等,而老婆同学只有一个“献血光荣”。相应的,我的方向感也经常成为老婆的鄙视对象,在反应时间很短的情况下,我经常会把左右弄反。例如今天早上去拍四维彩超,我在目的地门口兜了好几圈才“顺利”停车。(我对此的解释是,大脑发达的人往往小脑会有点不足^_^)

今天老婆打算给圈圈做一个尿布台,其实就是一个可以摆在婴儿床上的小板。在上面换尿布,可以不用弯腰,比较方便。于是给我布置了一个任务,给尿布台的两端钉上挡板,避免换尿布的时候板子滑下去。

需要固定两端的尿布台

需要固定两端的尿布台

我想这事儿也太简单了吧,弄两个木条钉在两边不就ok鸟。于是下午就在露台上叮叮咣咣的开始行动。

首先锯木条,露台上的木条很多,吭哧吭哧锯了两根出来。杯具出现了:因为木条很细,一敲钉子就裂开了;
心情很惆怅,重新锯宽一点的木条,发现尿布台的宽度和婴儿床基本一样宽,木条宽了装不上去;
郁闷中,跑出去买了一盒大头钉,回来试了下差点吐血,一敲就弯,根本钉不进去;
愤怒了,打算改用角铝来固定。考虑到角铝断面很尖,我决定用砂轮打磨一下;另外钉子也不能直接钉进去,需要打几个孔。

当时老婆正在厅里给圈圈做手工,惊讶的看到我带着护目镜和手套,抱着砂轮,电钻,角铝等重型武器上露台。只见她一脸鄙夷,钉几颗钉子怎么搞的像参加世界大战似的。随后给我了一盒工字钉,就是单位里经常看到,用来在布告栏钉照片的那种,钉上去一试正合适!

用来防止滑动的工字钉

用来防止滑动的工字钉

都说孕妇“生个孩子傻三年”,没想到家里的这位同学智商还可以。据其本人说,平时为了保护我那颗脆弱的自尊心,所以一直没敢表现出来,今天是实在看不下去了!

好吧,都说孩子的智商随妈妈,哈哈,看来圈圈将来会是个天才了。。。

最后转载个toooold的笑话,自嘲一下:
—————————————————————————
某厂引进了一条香皂包装生产线,结果发现这条生产线有个缺陷:常常会有盒子里没装入香皂。但总不能把空盒子卖给顾客啊,他们只得请了一个学自动化专业的博士设计一个方案来分拣空的香皂盒。

博士拉起了一个十几人的科研攻关小组,综合采用了机械、微电子、自动化、X射线探测等技术,花了几十万设计出了一个X射线探测器和一个自动机械手,成功解决了问题。每当生产线上有香皂盒通过时,X射线探测器就会检测到盒子里有没有装上东西,一旦发现是空盒子,自动机械手就会把空皂盒推走。

同样的,南方有个乡镇企业也买了这条生产线。老板发现这个问题后大为发火,找了个小工来说:“你xx的,不给老子把这个问题搞定,走人!”小工很快想出了办法:他花了90块钱在生产线旁边放了一台电风扇,调到合适的功率向着生产线不停的吹,于是空皂盒都会被吹走了,也解决了问题。

蓝牙手机变身小车遥控器 (1)

上篇博客提到我企图把手机改造成小爱的遥控器,这几天终于有点眉目了。这个小车刚组装好的时候,我就接上电池试运行了一下,结果它在屋里一溜小跑,紧赶慢赶才没让它撞到东西。这就是决定做一个遥控器的原因。本着“变废为宝,物尽其能”的DIY精神,我打算利用现有的手机来改造。

说起变废为宝,老婆大人一定心情很惆怅。因为大多数情况下,我喜欢拆东西,在家里干的都是些“变宝为废”的事情。但这次绝对是废物利用。我的手机是HTC钻石2,这款手机的系统是Windows Mobile;优点是CPU强大,屏幕细腻;缺点是经常丢短信,漏电话。也就是说,这款手机作为一个手机,基本可以认为是废物点心。好,接下来开始我们的变废为宝之旅吧。

第一次做手机上的开发,这段时间真是颇费周折。下面是我尝试的几个方案,供大家参考:

最初我想用类似控制萝卜头的办法,使用蓝牙串口向PC发送数据,结果发现并不是所有蓝牙连接都具有虚拟端口的功能。可以查看蓝牙支持的功能,那个Serial Port就是乐高机器人用来通讯的。

HTC手机的蓝牙,不支持Serial Port通信

HTC手机的蓝牙,不支持Serial Port通信

第二个方案是改用手机的WIFI功能,在PC上搭建一个网页,通过URL Request的方式向PC发送数据,非常杯具的是WIFI可以向公网IP发数据,但是不能向局域网内的笔记本发数据。经验证,我放在博客主机上的测试页面可以收到数据,虽然最终也没有成功,不过也算是进了一步。

第三次尝试又用回蓝牙,发现在ActiveSync连接模式下,手机共享的是笔记本的网络资源,这样就可以向自身发送URL Request了。经测试,数据流可以走通。正在欢欣鼓舞的时候,发现一件更杯具的事情:不知道为什么,每发送五六条数据之后,手机就像死机了一样,必须休息几分钟之后才能继续发送。这要是用来当遥控器,小爱怕早就把电视撞烂了。

接下来的几天没有什么进展,非常郁闷,以至于我经常萌生一些邪念(例如把手机扔进马桶)。事实证明最痛苦的时候往往已经接近成功了。有一天我把URL Request换成Web Service做了一次尝试,神奇的发现手机调用Web Service居然又快又不会死机。接下来的事情只能用峰回路转来形容,Web Service再通过TCP/IP协议把数据转发到一个Socket端口,一个端口监听程序再把数据通过USB发给Arduino开发板。经过这么多热心的同志,终于把鸡毛信从手机送到电机了,看看数据流图(其中WebService服务器和笔记本逻辑上是独立的,物理上是同一台电脑):

手机遥控器的数据流图

手机遥控器的数据流图

不知道会不会被手机开发的业内人士们鄙视,不过我至少摸索了一条没人走过的曲折道路,整个流程一共需要写四个程序:
1,在手机上运行的小程序,我画了一个方向盘,用手指触摸的时候,会换算成电机速度发送给Web Service。
   开发环境是Windows Mobile 6.5,使用的语言是C#
2,Web Service程序,接受指令之后,通过TCP/IP的方式转发。使用的语言还是C#,服务器是IIS。
3,端口监听以及Arduino开发板通信的程序。一边通过监听Socket端口接受2发来的指令,一边把指令通过模拟的串口发送给Arduino开发板。使用的开发语言还是C#。
4,Aruino开发板程序,这部分是通过模拟的串口接受指令,转换成电机对应的占空比电流脉冲,从而控制小车的两个直流电机。开发环境是Arduino 0017,开发的语言怀疑是类Java(软件上面有一个咖啡杯的图标)

回头一看,发现自己真够啰嗦的,写了半天还没见到代码,赶紧给标题后面加了个“1”。先贴两个程序的截图吧,改天再把代码发上来。

手机上的程序截图

手机上的程序截图

端口监听及转发程序截图

端口监听及转发程序截图

底盘小车 – 框架

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

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

打孔的地方

打孔的地方

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

工作室就是我家的阳台

工作室就是我家的阳台

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

轮子和轴承

轮子和轴承

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

划线

划线

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

木条制作的“老虎钳”

木条制作的“老虎钳”

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

打孔后的铝条

打孔后的铝条

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

检查打孔的尺寸

检查打孔的尺寸

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

底盘架子

底盘架子

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

轮子和直流电机

轮子和直流电机

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

万向轮

万向轮

最终的成果是这样的:

大功告成

大功告成

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

行百里者半九十

一月份的时候,网友bigapple建议大家一起翻译Lejos NXT的中文入门教程。当时很多同学报名领了任务,两周内就翻译了一大半。之后因为工作忙,我领的四篇只翻译了三篇半,最后半截始终没有完成(大苹果也是剩一篇^_^ )。

看来古人说的“行百里者半九十”真是非常贴切,事情越接近成功,越要集中精力认真对待。眼前就有另外一个例子:我的萝卜头攻略按照计划再两三篇就该收尾了,但是一直懒得把它们写完。好像很多人都是这样,坚持了很久,终于坚持不住放弃了,其实离成功只有一步之遥而已。

今天晚上老婆突然告诉我,翻译要坚持翻完,她这几天悄悄的帮我翻译了三篇。现在只剩下最后的2.5篇了。真是非常感谢老婆!我一定会坚持把这个Lejos教程和萝卜头的攻略都写完!

翻译好的教程看这里,其中标记了ok的就是翻好的:
http://www.diy-robots.com/resources/LejosNxtTutorial_cn/index.aspx