Archive for the ‘小爱成长记’ Category

Arduino开发板实验四:步进电机控制

上周总算做成了点事,其实很简单,就是用Arduino实现了步进电机的正转和反转。因为总是很忙,所以拖到现在才有时间补上攻略。感慨一下,IT民工真辛苦啊,有位同事的昵称已经改成 “还是古代好,切掉小JJ就可以当公务员了”。 好吧,祝这位朋友心想事成,我还是坚持当民工好了 :)

在步进电机实验前,从网上找到了一个关于步进电机驱动的文档,使用的是L298N的驱动芯片。这个文档里面有些错误,导致我浪费了大量时间。也许不同的电机和芯片版本也许有区别吧,请大家慎重使用。先借用一下原理图:

L298N步进电机驱动芯片原理图

错误的L298N步进电机驱动芯片原理图

其中IN1~IN4以及ENA,ENB在之前的一篇关于直流电机驱动中有介绍过,分别对应输入的六个管脚。这个图里有两处错误,首先可以看到有两个ENA,其中一个应该是ENB;另外这两个EN都是接地的,但是经我实验看来,应该接+5V的电压才对。

所以正确的原理图应该是这样的:

正确的L298N原理图

正确的L298N原理图

下面是对应的接线图:

乱七八糟的接线图

乱七八糟的接线图

接线之后按照说明书里的时序图写了一段程序,呼呼,一次就通过了电机的正转实验。可是在企图实现反转的时候,总是不成功。在焦头烂额之后,终于开始怀疑文档是否正确。事实证明,大家做任何事情都要相信伟大的党而不是万恶的“文档”,下面是错误的反转时序图和经我验证可行的时序图:

步进电机驱动的时序图

步进电机驱动的时序图

基于以上时序图,我写了一段代码,让步进电机实现下面的动作:
正转一圈 -> 暂停1秒钟 -> 反转一圈 -> 暂停一秒钟 ->循环

代码如下:

int LeftI1 = 28;     //连接电机驱动板的I1接口
int LeftI2 = 22;     //连接电机驱动板的I2接口
int LeftEA = 8;      //连接电机驱动板的EA接口
int RightI1 = 36;    //连接电机驱动板的I1接口
int RightI2 = 42;    //连接电机驱动板的I2接口
int RightEB = 6;     //连接电机驱动板的EB接口
int StepCount = 0;
int StepDelayTime=1500;

void setup()
{
  pinMode(LeftI1, OUTPUT);     //I1和I2都是数字信号
  pinMode(LeftI2, OUTPUT);     //通过设置I1和I2来控制电机旋转方向
  pinMode(LeftEA, OUTPUT);     //按占空比方式输出的模拟信号
  pinMode(RightI1, OUTPUT);    //I1和I2都是数字信号
  pinMode(RightI2, OUTPUT);    //通过设置I1和I2来控制电机旋转方向
  pinMode(RightEB, OUTPUT);    //按占空比方式输出的模拟信号
  Serial.begin(9600);          //设置波特率
}
void ForwardInit()
{
  digitalWrite(LeftEA, HIGH);
  digitalWrite(RightEB,HIGH );
  digitalWrite(LeftI1, LOW);
  digitalWrite(LeftI2,HIGH );
  digitalWrite(RightI1,HIGH);
  digitalWrite(RightI2, HIGH);
  StepCount=0;
}
void BackwardInit()
{
  digitalWrite(LeftEA, HIGH);
  digitalWrite(RightEB,HIGH );
  digitalWrite(LeftI1, LOW);
  digitalWrite(LeftI2,LOW );
  digitalWrite(RightI1,LOW);
  digitalWrite(RightI2, HIGH);
  StepCount=0;
}
void ForwardOneStep()
{
  delayMicroseconds(StepDelayTime);
  switch(StepCount)
  {
    case 0:
      digitalWrite(RightI2,LOW);
      digitalWrite(LeftI1,HIGH);
      break;
    case 1:
      digitalWrite(RightI1,LOW);
      digitalWrite(RightI2,HIGH);
      break;
    case 2:
      digitalWrite(LeftI2,LOW);
      digitalWrite(RightI1,HIGH);
      break;
    case 3:
      digitalWrite(LeftI1,LOW);
      digitalWrite(LeftI2,HIGH);
      break;
  }
  StepCount=(StepCount + 1) % 4;
}

void BackwardOneStep()
{
  delayMicroseconds(StepDelayTime);
  switch(StepCount)
  {
    case 0:
      digitalWrite(RightI2,LOW);
      digitalWrite(LeftI1,HIGH);
      break;
    case 1:
      digitalWrite(LeftI1,LOW);
      digitalWrite(LeftI2,HIGH);
      break;
    case 2:
      digitalWrite(LeftI2,LOW);
      digitalWrite(RightI1,HIGH);
      break;
    case 3:
      digitalWrite(RightI1,LOW);
      digitalWrite(RightI2,HIGH);
      break;
  }
  StepCount=(StepCount + 1) % 4;
}

void loop()
{
  while(1)
  {
    ForwardInit();
    for(int i=0;i<200;i++)
    {
      ForwardOneStep();
    }
    delay(1000);
    BackwardInit();
    for(int i=0;i<200;i++)
    {
      BackwardOneStep();
    }
    delay(1000);
  }
}

除了实现了动作之外,我还搭车实验了下面几件事情:

1,步进电机的转角相当精确,我捆了根电线当指针,反复转了几百圈之后,指针的位置几乎没有变化

2,扭矩还挺大,我选用的是标称扭矩是3.4Kg.cm的步进电机,用铅酸蓄电池供电,旋转时我用爪子完全不能把它捏住(NXT的电机貌似没有这么强劲)。

3,经我测试,每个脉冲之间的间距最好大于1500μs(1.5ms),如果间距太小的话,就会出现失步的情况。

思考问题:基本上来说,每个步进电机都需要一个驱动板(L298N)和一个控制板(Arduino或其它单片机)。如果需要控制多个电机的话(小爱也许会有20多个关节),买这么多板子成本就太高了。实际上,每个脉冲间距之间有1500微秒的空闲时间,对CPU来说简直是漫漫长夜。所以我觉得可以用类似于操作系统多任务的思想来生成时序,充分利用脉冲间距之间的剩余价值,这样就可以只用一块Arduino实验板来控制多个电机了。

呵呵,又想多了,等下周有空再试试吧!

蓝牙手机变身小车遥控器 (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

蓝牙手机变身小车遥控器 (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线,所以暂时还不能实现遥控。这几天正在试验把我的手机作成遥控器,如果能搞定的话发上来跟大家分享。另外萝卜头的攻略还差几篇,接下来这段时间争取把它们写完。

Arduino开发板实验四:串口通讯,通过计算机控制舵机

前几天肩膀可能是拉伤了,休息了几天。先回答一个朋友们比较关心的问题,那一对直流电机的扭矩差不多是30kg*cm。前几天我已经接上电源,并且压了一些重物,看上去在室内平地可以轻松带动(爬坡没有测试)。因为还没有写电机的遥控程序,所以只是用原地打转做测试。按照我的计划,笔记本电脑将会作为一个配件,安装在小爱的胸前。所以今天做了一个串口通信的小实验,将来也要通过计算机这样控制小爱的各种运动。

实验目标是:做一个小程序,通过鼠标拖拽来控制舵机的角度,计算机和Arduino实验板之间使用USB线连接。

首先看一下接线图:

舵机接线图

舵机接线图

舵机控制的命令可以参考之前的小实验:Arduino开发板实验三(舵机控制)。先看看我们这个实验里需要用到的几个串口通信命令:

Serial.begin(9600);  //设置波特率
Serial.available();  //如果有数据传来,这个值大于0
int readValue = Serial.read();  //读取一个字节的数据

这个实验里只需要从计算机接受数据,如果需要发送数据的话,可以使用下面的命令:

Serial.print();
Serial.println();
Serial.write();
Serial.flush();

具体的用法可以去Arduino的官网上查看: http://arduino.cc/en/Reference/Serial

在Arduino端的程序如下:

void loop()
{
  while (Serial.available() > 0)
  {
    //读取计算机发送的角度值
    readValue = Serial.read();
  }
  //发送50个脉冲
  for(int i=0;i<50;i++)
  {
     //引用脉冲函数
     servopulse(readValue);
  }
}

计算机端的程序使用C#编写,Arduino使用USB连接计算机以后,其实也被映射到一个端口,所以连接的方法和蓝牙连接类似,可以参考萝卜头的蓝牙通讯部分。

下面是小程序的界面:

计算机上运行的小程序

计算机上运行的小程序

创建一个从0到180的轨道条(TrackBar,也有人叫它滑尺),当滑尺位置变换时,就把设置的角度发送到指定的端口上。代码如下:

        private void AngleTrack_Scroll(object sender, EventArgs e)
        {
            ReadValue.Text = AngleTrack.Value.ToString();
            if (serialConn != null && serialConn.IsOpen)
            {
                BlueToothDataSend(new byte[] { Convert.ToByte(ReadValue.Text) });
            }
        }

        private SerialPort serialConn;
        private void ConnectButton_Click(object sender, EventArgs e)
        {
            serialConn = new SerialPort();
            ConnectButton.Enabled = false;
            serialConn.PortName = PortNumber.Text;
            serialConn.Open();
            serialConn.ReadTimeout = 10000;
        }

        private void BlueToothDataSend(byte[] data)
        {
            int length = data.Length;
            byte[] readData = new byte[length + 2];
            readData[0] = (byte)(length % 255);
            readData[1] = (byte)(length / 255);
            for (int i = 0; i < length; i++)
            {
                readData[i + 2] = data[i];
            }
            serialConn.Write(readData, 0, length + 2);
        }

实验结果:拖动轨道条可以实现对舵机的控制,但是在0~30和150~180的区间,舵机是不动的;在30~150区间,舵机基本能按照鼠标拖动的角度旋转。结果表示串口通信成功了,但同时也说明这个舵机的实际转角只能达到120度左右,并且控制并不是特别精确。这意味着将来做机械臂的时候,可能会有很大的误差。头大中…..早知道就选步进电机了,不过一口吃不成胖子,慢慢来吧,硬件的误差可以通过软件来弥补。

工具啊工具

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

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

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

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

有点雏形的小车底盘

有点雏形的小车底盘

底盘小车的制作 – 轮子

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

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

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

小车的轴

小车的轴

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

各种车床配件

各种车床配件

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

百变菜板

百变菜板

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

电脑桌下面的角铁

电脑桌下面的角铁

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

直流电机的支架

直流电机的支架

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

小型车床

小型车床

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

打磨短轴

打磨短轴

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

安装轮子

安装轮子

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

锥齿轮固定

锥齿轮固定

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

做好的轮子

做好的轮子

Arduino开发板实验三:舵机控制

经常玩NXT的朋友肯定对NXT的电机印象深刻,使用非常方便。转速,角度和方向都可以随意控制。

在计划制作小爱的时候,我也一直希望能找到这样的电机。查了一些资料,觉得比较容易控制的有舵机和步进电机。舵机的主要玩家是船模和航模的爱好者们。大海航行靠舵手,舵机就是用来控制舵角的,它的最大特点是可以方便的控制角度,它的限制是舵角一般不超过180度。步进电机就强多了,既可以控制角度,还可以连续旋转,它的问题是输出就是一个光轴,需要加工配套的零件才能使用,另外价格好像会更贵一点。

我计划用舵机来实现小爱的机械臂,最主要的考虑原因是舵机自带很多舵角之类的配件,比较容易安装,毕竟机械加工是制作过程中最麻烦的部分。另外,一般机械臂的关节转角也不需要大于180度,用舵机就足够了。下面是使用Arduino开发板控制舵机的一个小实验。

先抄一段说明:舵机,又称伺服马达,是一种具有闭环控制系统的机电结构。舵机主要是由外壳、电路板、无核心马达、齿轮与位置检测器所构成。其工作原理是由控制器发出PWM(脉冲宽度调制)信号给舵机,经电路板上的IC处理后计算出转动方向,再驱动无核心马达转动,透过减速齿轮将动力传至摆臂,同时由位置检测器(电位器)返回位置信号,判断是否已经到达设定位置,一般舵机只能旋转180度。

舵机结构图

舵机结构图

舵机有3根线,棕色为地,红色为电源正,橙色为信号线,但不同牌子的舵机,线的颜色可能不同,请大家注意。

舵机的转动的角度是通过调节PWM(脉冲宽度调制)信号的占空比来实现的,标准PWM(脉冲宽度调制)信号的周期固定为20ms(50Hz),理论上脉宽分布应在1ms到2ms之间,但是,事实上脉宽可由0.5ms到2.5ms之间,脉宽和舵机的转角0°~180°相对应。有一点值得注意的地方,由于舵机牌子不同,对于同一信号,不同牌子的舵机旋转的角度也会有所不同。

舵机角度和占空比的关系

舵机角度和占空比的关系

 下面这个小实验的目标是用电位器控制舵机的角度,正好在前一个实验里,电位器都还没有拆掉。需要特别注意的是供电部分,舵机转动时电流会比较大,Arduino上的电源芯片可能会因过流保护到发热而损坏,电源需要接到外部供电,切不可使用USB供电。
舵机的棕色线接GND,红色线接VIN(我猜这个是直接连到外接电源的正极),黄色是数据线,接在PWM的7号管脚。电位器的连接稍微有点变换,因为管脚们施展不开,我把正极连在3.3V的接口上,这样模拟输入的范围就变成了0到660左右。前面说了,舵机分别用0.5ms到2.5ms之间的脉冲来对应0到180度左右的角度,我们可以用pulsewidth=(angle*11)+500这样的公式,把0到180度的转角映射到500到2480的脉冲时间。

接线图

接线图

下面看代码:

int readPin = 6;   //用来连接电位器
int servopin = 7;    //定义舵机接口数字接口7

void servopulse(int angle)//定义一个脉冲函数
{
  int pulsewidth=(angle*11)+500;  //将角度转化为500-2480的脉宽值
  digitalWrite(servopin,HIGH);    //将舵机接口电平至高
  delayMicroseconds(pulsewidth);  //延时脉宽值的微秒数
  digitalWrite(servopin,LOW);     //将舵机接口电平至低
  delayMicroseconds(20000-pulsewidth);
}

void setup()
{
   pinMode(servopin,OUTPUT);//设定舵机接口为输出接口
}

void loop()
{
  //读取电位器(传感器)的读数,接到3.3V,值范围从0到660左右
  int readValue = analogRead(readPin);
  //把值的范围映射到0到165左右
  int angle = readValue / 4;
  //发送50个脉冲
  for(int i=0;i<50;i++)
  {
     //引用脉冲函数
     servopulse(angle);
  }
}

实验结果:当旋转电位器的时候,舵机的角度随之改变。不过最终转角并没有达到180度,在某些范围内,电位器旋转时,舵机没有转动。网上舵机的说明也提到了这点,识别的角度范围是有限的。具体的有效角度范围,我还没有测量,等将来开始制作的时候再说。

疯狂大采购

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

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

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

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

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

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

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

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

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

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

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

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

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

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

各种轴承

各种轴承

无数默默无闻的螺丝钉

无数默默无闻的螺丝钉

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