找回密码
 马上注册

QQ登录

只需一步,快速开始

楼主: James.Yang

[教程] NXC简明教程(中文版)——自主翻译

  [复制链接]
 楼主| 发表于 2013-4-24 19:29:01 | 显示全部楼层
不用整理,我翻译完后,会将PDF文档发上来的。若有错误,请各位指出,以便我最终修订时更正。
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-4-25 20:23:41 | 显示全部楼层
第八章 进一步理解电机
你可以使用一些额外的电机指令,来更精确地控制电机。在本章中,我们将讨论他们: ResetTachoCount,Coast(Float),OnFwdReg,OnRevReg,OnFwdSync,OnRevSync,RotateMotor,RotateMotorEx和基本的PID概念。
平稳停止
当你使用Off()命令时,伺服电机会立即停止,抱住传动轴并保持位置。使用刹车停止外,也可以让电机以平稳的方式停止。对于这种方式我们一般使用Float()或Coast()命令,它们只是简单地切断电机的供电。下面是一个例子。首先,机器人使用刹车停止;然后不采用刹车停止。请注意其中的差别。其实,对这个特殊机器人来说其差异是非常小的。但是,对其他的机器人来说会有很大的差异。

图8-1 刹车停止及滑行停止

高级命令
命令OnFwd()和OnRev()是移动电机最简单的例程。
NXT伺服电机有一个内置的编码器,可以让你精确控制传动轴的位置和速度。
NXT硬件通过使用编码器作为反馈执行PID(比例积分微分)闭环控制器来控制电机的位置和速度。
如果你想让机器人笔直前进,你可以使用同步功能,它能使选定的一对电机同时运动,当其中之一速度变缓甚至受阻时,另一方会等待对方;以同样的方式,你可以设置一对电机以一定的转向比例同步运行,来完成左转、右转或原地打转,但始终保持同步。有很多命令可以充分发挥伺服电机的功能!
OnFwdReg('ports','speed','regmode’)运用调节模式OUT_REGMODE_IDLE,OUT_REGMODE_SPEED或OUT_REGMODE_SYNC以指定“速度”的功率驱动指定“端口”的电机前进。如果选择IDLE模式,将不采用PID调节模块;如果选择SPEED模式,即使电机的负载有变化,NXT调节单个电机以得到一个恒定的速度;最后,如果选择SYNC模式,就如上述介绍的指定端口中的一对电机将同步运行。
OnRevReg()运行方式同上述命令,只是改变了一下方向。

图8-2 OnFwdReg举例

该程序显示了当你尝试停止你手中机器人的轮子时,各种不同调节模式的不同点:首先使用IDLE模式,停止一个轮子,你不会注意到任何变化;然后使用SPEED模式,尝试降低一个轮子的速度,你将会看到NXT会提高电机功率,以克服你的阻力来努力保持恒定速度,最后使用SYNC模式,停止一个轮子会导致另外一个轮子也停下来,来等待被阻止的轮子运转。
OnFwdSync('ports','speed','turnpct’)与OnFwdReg()命令在同步模式下是一样的,但现在你可以指定转向百分比“turnpct”(从-100到100)。
OnRevSync()同上述命令一样,只不过改变了电机的方向。下面的程序显示了这些命令:尝试改变转向数字,来看看它的行为:
.
图8-3 OnFwdSync和OnRevSync举例

最后,电机也可以设置为转动有限的度数(记住,一整圈为360°).
对下面的两种命令,你可以通过给速度或者角度数一个符号让电机改变方向:因此,如果速度和角度具有相同的符号,电机向前运行,如果他们具有相反的符号,电机向后运行。
RotateMotor('ports','speed','degree')对指定端口(port)的电机以指定速度(Speed)及功率值(在0-100范围内)旋转电机轴转过一定的角度数(degree)。

图8-4 RotateMotor举例

RotateMotorEx('port','speed’,'degrees','turnpct','sync','stop')是上述命令的一个扩展,它可以让你按指定的转向百分比“turnpct”(从-100到100)和一个布尔标志“sync”(可以设置为true或false)来同步两个电机(例如OUT_AC)。它也可以通过布尔标志”stop”让你指定在电机完成转动的角度后是否采取刹车停止。

图8-5 RotateMotorEx举例

PID控制
NXT硬件通过数字PID(比例积分微分)控制器来精确调节伺服电机的位置和速度。此类控制器是一个最简单但最有效的闭环反馈控制,称为自动化,经常被使用。
简单说来,它的工作原理如下(我将讨论离散时间控制器的位置调整):
你的程序给了控制器一个要达到的设置值R(t),它用一个命令U(t)来驱动电机,使用其内置的编码器测量其位置Y(t)并计算误差E(t)= R(t) - Y(t):这就是为什么它被称为“闭环控制”,因为输出位置Y(t)返回给控制器作为输入以计算误差。控制器再将误差E(t)转换为命令U(t),因此:

U(t) = P(t) + I(t) + D(t), 其中
P(t) = KP•E(t),
I(t) = KI•(I(t–1) + E(t))
及D(t) = KD•(E(t) – E(t–1)).

对于一个新手来说这可能看起来相当复杂,但我会尽我所能来解释这个机制。
该命令是三个部分之和,比例部分P(t),积分部分I(t)和微分部分D(t)。
P(t)能使控制器快速响应,但它并不保证在平衡状态没有错误。
I(t)给控制器“记忆”,在这个意义上,它跟踪累积误差,并补偿它们,并确保在平衡状态下零误差。
D(t)给控制器“未来预测”(如同数学上的微分),提高反应时间。
相比于对这些参数用整本学术专著来进行介绍,我知道上述解释仍然很混乱!但我们仍然可以用我们的NXT智能积木块在线尝试一下!使用内存解决问题的简单程序如下所示。

图8-6 一个简单的PID程序

命令RotateMotorPID(port, speed, angle, Pgain, Igain, Dgain)允许设置默认值以外的PID增益来移动电机。尝试设置以下数值:
(50, 0, 0):电机不能准确转动180°,因为存在不能补偿的错误。
(0, X, X):没有比例部分,这是一个非常大的错误
(40, 40, 0):存在过冲现象,也就是说电机轴转动超出设定值后,然后再返回。
(40, 40, 90):精度良好,但增加了时间(到达设定点的时间)。
(40, 40, 200):电机轴来回振荡,因为微分增益太高。
请尝试其他的值,来观察这些增益值如何影响电机的性能。
小结
在本章中,你学到了可用于电机的高级命令:Float(),Coast()平稳的停止电机;OnXxxReg()和OnXxxSync(),允许反馈控制电机的速度和同步;RotateMotor()和RotateMotorEx()用精确度数来转动电机轴。你也学到了关于PID控制一些内容,但并没有一个详尽的解释,也许我已经在你心里引起了一些好奇心:上网搜索有关内容!
图8-1.JPG
图8-2.JPG
图8-3.JPG
图8-4.JPG
图8-5.JPG
图8-6.JPG
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2013-4-27 12:28:47 | 显示全部楼层
搂主精神高尚,其实很多人都看过,但懒得翻译,或看得懂,但翻译不好,对搂住的精神赞一个。
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-4-30 19:35:56 | 显示全部楼层
第九章 进一步理解传感器
在第五章中,我们讨论了使用传感器的基本知识。但是,可以使用传感器做更多的事情。在本章中,我们将讨论传感器模式和传感器类型之间的区别,并将看到如何使用乐高转换电缆将老式的兼容RCX传感器连接到NXT,并使用他们。
传感器模式和类型
我们之前看到的SetSensor()命令实际上完成两件事情:它设置了传感器的类型,以及传感器的工作模式。通过分开设置传感器的模式和类型,你可以更精确地控制传感器的行为,对一些特殊应用,这是有用的。
传感器的类型设置使用命令SetSensorType()。有许多种不同的传感器类型,但我在这里只介绍一些主要的类型:SENSOR_TYPE_TOUCH,这是触摸传感器类型,SENSOR_TYPE_LIGHT_ACTIVE,这是光线传感器类型(本身的LED灯打开),SENSOR_TYPE_SOUND_DB,这是声音传感器,及SENSOR_TYPE_LOWSPEED_9V,这是超声波传感器。设置传感器类型特别重要,它用来表明该传感器是否需要电源(例如,光线传感器中点亮LED),或者告诉NXT该传感器是数字量信号并通过I2C串行协议进行读取。在NXT上是可以使用旧的RCX传感器的:SENSOR_TYPE_TEMPERATURE,这是温度传感器,SENSOR_TYPE_LIGHT为老的光线传感器,SENSOR_TYPE_ROTATION为RCX的旋转传感器(此类型将在后面讨论)。
传感器的模式设置使用命令SetSensorMode()。一共有8种不同的模式。其中最重要的是SENSOR_MODE_RAW。在此模式中,当检查传感器时你得到的值是0和1023之间的一个数。它是由传感器产生的原始值。具体这个数意味着什么取决于实际的传感器。例如,对于触摸传感器,当传感器没有被按下时,其值接近1023。当它被完全按下时,这个值接近50。当它被部分按下时,其值的范围在50和1000之间。所以,如果你将触摸传感器设置为原始模式,你能真正知道传感器是否被部分按下。当传感器为光线传感器时,其取值范围约为300(很亮)到800(非常暗)。这比使用SetSensor()命令得到一个更为精确的值。有关详细信息,请参阅NXC编程指南。
传感器的第二种模式是SENSOR_MODE_BOOL。在这种模式下其值为0或1。当原始值大于562时其值为0,否则为1。模式SENSOR_MODE_BOOL是触摸传感器的默认模式,但也可以使用于其他传感器类型,但摈弃其模拟信息。模式SENSOR_MODE_CELSIUS及SENSOR_MODE_FAHRENHEIT仅对温度传感器有用,并按指定单位显示温度。模式SENSOR_MODE_PERCENT将原始值转换为一个介于0和100之间的值。SENSOR_MODE_PERCENT是光线传感器的默认模式。 SENSOR_MODE_ROTATION仅适用于旋转传感器(见下文)。
还有其他两个有趣的模式:SENSOR_MODE_EDGE和SENSOR_MODE_PULSE。他们统计转换次数,也就是原始值从低到高或相反的变化。例如,当你按下触摸传感器,这就会引起原始值由高到低的变化。当你释放它,你会得到一个相反的变化。当你将传感器模式设定为SENSOR_MODE_PULSE时,只统计从低到高的转换次数。因此,触摸传感器每一次按下及释放计数为1。当你将传感器模式设定为SENSOR_MODE_EDGE时,两个转换都要计数。因此,触摸传感器每一次按下及释放计数为2。这样,你就可以用它来统计触摸传感器多久会按下。或者你可以结合光线传感器来计算(强)灯的开启和关闭频率。当然,当你统计边沿或脉冲数时,你应该能够将值设置回0。你可以使用命令ClearSensor()来完成它,该命令将指定传感器的计数器清零。
让我们来看一个例子。下面的程序使用触摸传感器来操控机器人。用一根长线联接触摸传感器来进行输入。如果快速按下触摸传感器两次,机器人向前移动。如果你只按下一次,机器人停止不动。

图9-1 触摸传感器例子

注意,我们首先设置了传感器的类型,然后设置传感器模式。看来这是基本要求,因为改变传感器类型会影响传感器模式。
旋转传感器
旋转传感器是一个非常有用的传感器类型:它是一种光学编码器,与NXT伺服电机内置传感器几乎相同。旋转传感器有个小孔,孔中可以放置一根轴,然后测量相对角度位置。轴的一整圈分为16等分(或-16,如果以反方向旋转),这意味着其分辨率为22.5度,相对于伺服电机1度分辨率来说是非常粗糙的。这种老式的旋转传感器仍然有用,它不需要消耗电机功率就可以监测轴,使用电机作为编码器,需要很大的扭矩来驱动它,而老式的旋转传感器是很容易旋转的。
如果你每圈需要比16等分更高的分辨率,你可以使用齿轮,机械地增加每圈的测量数。
下面的例子是继承自关于RCX的老教程。
一个标准的应用是将两个旋转传感器连接到用两个电机控制机器人运动的两个轮子上。对于直线运动,你希望两个轮子转得一样快。不幸的是,电机通常不以完全相同的速度运转。使用旋转传感器,你可以看到一个轮了转得快一些。然后,你可以暂时停止该电机运转(最好使用float()),直到两个传感器反馈相同的值。下面的程序就做到了这一点。它简单地让机器人沿直线运动。要使用这个程序,将两个旋转传感器连接到两个轮子上来改变你的机器人。并将传感器连接到输入端口1和3。

图9-2 旋转传感器例子

该程序首先指明两个传感器都为旋转传感器,并将其值重置为0。然后开始一个死循环。在循环中,我们检查两个传感器的读数是否相等。如果相等,机器人向前移动。如果一个值大,则值大的电机停止运动,直到两个电机的读数都再次相等。
很明显这是一个非常简单的程序。你可以将其扩展使机器人移动精确的距离,或者让它完成非常精确的转弯。
在一个输入端口连接多个传感器
在本小节的开始需要一个小小的免责声明!由于改进的NXT传感器和6根电缆线的新结构,在同一端口连接多个传感器不再象以前那么容易(象RCX传感器一样)。老实说,唯一可靠(且容易做到)的应用是通过使用转换线缆建立一个触摸传感器的模拟多路复用器。另一种选择是能管理与NXT进行I2C通信的复杂的数字多路复用器,但是这对于初学者来说绝对不是一个合适的解决方案。
NXT有四个连接传感器的输入端口。当你想做出更复杂的机器人(或你购买了一些额外的传感器),这可能对你来说不够了。幸运的是,通过一些小技巧,你可以连接两个(或更多)的传感器到一个输入端口。
最简单的是将两个触摸传感器连接到一个输入端口。如果其中之一(或两者)被按下,其值为1,否则为0。你不能区分这两个传感器,但有时没有必要区分。例如,当你把一个触摸传感器安装在机器人前面,一个安装在后面,你可以通过机器人移动的方向来知道哪一个传感器被按下。但是你也可以设置输入为原始值模式(见上文)。现在你可以得到更多的信息。如果你很幸运,两个传感器按下时的值是不一样的。如果是这样的话,你可以真正区分两个传感器。而当两者都按下时,将得到一个较低的值(约30),这样你也可以将他们区分出来。
你还可以将触摸传感器和光线传感器连接到一个输入端口(只限于RCX传感器)。将类型设置为光线传感器(否则光线传感器将不能正常工作)。将模式设置为原始值。在这种情况下,当触摸传感器被按下时,你得到一个低于100的原始值。如果触摸传感器没有被按下,你将得到光线传感器数值,这个值不会低于100。下面的程序使用了这种方法。机器人的光线传感器必须配置为向下,前保险杠连接一个触摸传感器,将他们连接到输入端口1。该机器人将在有光线的区域内随机运动。当光线传感器检测到暗线(原始值> 750),机器人往回走一点。当触摸传感器碰到什么东西(原始值在100以下),机器人也往回走一点。程序如下:

图9-3 触摸传感器与光线传感器组合例子

我希望这个程序简单明了。程序有两个任务。任务moverandom使机器人随机运动。主任务首先启动moverandom,设置传感器,然后等待事情发生。如果传感器的读数太低(按下)或过高(出了白色区域)就停止随机运动,往回走一点,然后再次启动随机运动。
小结
在本章中,我们学习到了有关传感器的一些额外的问题。我们看到了如何分别设置传感器的类型和模式,以及怎样用来获得额外的信息。我们学会了如何使用旋转传感器。我们还看到了如何将多个传感器连接到NXT的一个输入端口。所有这些技巧对构建更复杂的机器人时是非常有用的。传感器始终发挥着至关重要的作用。
图9-1.JPG
图9-2.JPG
图9-3.JPG
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-5-3 20:53:15 | 显示全部楼层
第十章 并行任务
正如前面指出的一样,在NXC中任务是同时执行的,或者如人们通常所说的平行运行。这是非常有用的。它使你能够在一个任务中监测传感器时,另一个任务却让机器人随意运动,而另一个任务却在播放一些音乐。但是,并行任务也可能导致问题。一个任务可能会与另一个任务发生冲突。
一个错误的程序
请看下面的程序。其间有一个任务驱动机器人沿正方形移动(就像我们以前经常这样做的一样),第二个任务检查触摸传感器。当触摸传感器被按下时,它向后移动一点,然后做个90度的转弯。

图10-1 一个错误的程序

这看起来好像一个完全有效的程序。但是,当你执行它时,你很可能会发现一些意想不到的行为。尝试以下操作:当机器人在转向时使它碰到一些东西,这时机器人会往回走,但随后再次向前移动,撞击障碍物。这种行为发生的原因是,任务间可能产生了干扰。就会发生接下来这些事情。机器人正在右转时,也就是第一个任务运行到其第二个等待语句。这时机器人碰到了传感器。它开始后退,但在同一时刻,主任务结束等待准备再次向前移动,这样机器人就撞上障碍物。第二个任务在这一时刻处于等待状态,所以它不会注意到冲突。这显然不是我们希望看到的行为。现在的问题是,当第二个任务处于等待状态时,我们没有意识到第一个任务仍在运行,这样其行为就干预了第二项任务的行动。
临界区和互斥变量
解决这个问题的方法之一是,确保在任何时刻只有一个任务在驱动机器人。这就是我们在第六章中所采取的方法。我在这里再重复一下这个程序。

图10-2 互斥程序

解决问题的关键是,无论是check_sensors还是move_square任务,都只能在没有其他任务使用电机时才能去控制电机:即在使用电机前通过使用Acquire语句来等待moveMutex互斥变量被释放。Acquire命令对等的命令是Release命令,该命令释放互斥变量以使其它任务能使用临界资源,我们程序中的临界资源为电机。在Acquire及Release命令之间的代码称为临界区:临界意味着有资源共享。通过这种方法任务间就不会有相互干扰。
使用信号灯
有一个能对互斥变量明确执行Acquire及Release命令的人工替代方法。
解决这个问题的标准方法是使用一个变量来表明哪个任务在控制电机。其他任务在第一个任务通过变量表明它已经使用完毕前不允许操作电机。这样的一个变量通常被称为信号灯。我们用sem来表示这样一个信号灯(如同互斥变量)。我们假设0表示没有任务在操作电机(资源空闲)。现在,每当一个任务想要操作电机时,将执行以下命令:

图10-3 信号灯使用方式

因此首先我们等待没有人占用电机。然后,我们通过将sem设置为1来申明对电机的控制。现在,我们可以控制电机。当我们完成电机操作后,我们将sem设置回0。下面你可以看到使用信号灯来实现上面程序中的互斥。当触摸传感器碰到了物品,设置信号灯并执行后退过程。在此过程中,任务move_square必须等待。当后退过程完成后,信号灯被设置为0,任务move_square继续。

图10-4 使用信号灯的程序
你可能会说,在任务move_square中没有必要将信号灯设置为1,再设置回0。但我还是觉得这是非常有用的。原因是,OnFwd()命令实际上是由两个命令组成(见第八章)。你不想让这个命令顺序被其他任务打断。
信号灯是非常有用的,当你在编写执行并行任务的复杂程序时,他们几乎总是需要的。(但仍有一些机会可能会失败。要尝试找出原因。)
小结
在本章中,我们研究了在多任务下可能出现的一些问题。对多任务的副作用一定要非常小心。许多无法预期的行为就缘于此。我们还学习了两种解决这些问题的不同方法。第一个解决方案是停止及重新启动任务,以确保在同一时刻只有一个临界任务在运行。第二种方法使用信号灯来控制任务的执行。这保证了在同一个时刻只有一个任务在执行临界部分。
图10-1.JPG
图10-2.JPG
图10-3.JPG
图10-4.JPG
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-5-6 19:50:23 | 显示全部楼层
第十一章 机器人之间的通信
如果你拥有一个以上的NXT,这一章就是为你而设(虽然你仍然可以通过单台NXT与PC进行数据通信)。机器人可以通过蓝牙无线技术互相通信:你可以使多台机器人协作(或相互争斗),你可以使用两台NXT建立一个大型的复杂的机器人,这样你可以使用6个电机和8个传感器。
对良好的老式RCX,这很简单:它发出红外线消息,周围所有的机器人都能接收。
对于NXT,这将是一个完全不同的方式!首先,你必须通过智能积木块上的蓝牙菜单来连接两个或更多NXT(或NXT与PC连接),只有这样,你才可以将消息发送到连接的设备。
发起连接的NXT被称为主机,通过通道1,2,3最多可以连接3个从设备。从设备总是将主设备连接到通道0。你可以发送消息到10个可用邮箱。
主-从设备通讯
举两个程序例子,一个为主设备,一个为从设备。这些基本的程序将教你如何通过两个NXT无线网络来管理快速连续的字符串消息流。
主程序首先通过BluetoothStatus(conn)函数来检查从设备是否正确连接在通道1上(BT_CONN常数),然后通过SendRemoteString(conn,queue,string)生成并发送以M打头的递增数字串消息,而通过ReceiveRemoteString(queue,clear,string)从从设备接收消息并显示数据。

图11-1 主-从设备通讯
从设备的程序非常相似,只不过使用SendResponseString(queue,string),替代SendRemoteString,因为从设备只可以给它的主设备——通道0——发送信息。

图11-2 从-主设备通讯

你可能注意到,中止其中一个程序,另一个程序将继续发送递增数字串的消息,而并不知道它所有发出的消息都将丢失,因为没有程序在侦听另一个程序。为了避免这个问题,我们可以规划一个更好的协议来相互确认消息的发送。
发送确认号码
下面再举一些例程:这次主设备用SendRemoteNumber(conn,queue,number)来发送数字并等待从设备进行确认(ack)(在until循环内,我们可以看到有ReceiveRemoteString),只有当从设备监听到并发送确认信号后,主设备才接着发送下一条消息。从设备使用ReceiveRemoteNumber(queue,clear,number)简单接收数据并通过SendResponseNumber发送确认信号。你的主从程序必须有共同的确认码,在这些程序中,我选择了十六进制数0xFF。
主设备发送一些随机数,并等待从设备确认,每当收到一个正确的确认码,确认(ack)变量必须被清除,否则,主设备将在没有新确认码下继续发送,因为确认变量成了脏变量。
从设备持续检查邮箱,如果它不为空,显示读取的数值,并给主设备发送一个确认信号。在程序开头,我在没有读取信息情况下直接发送确认信号以防阻塞主设备,事实上,如查没有这一技巧,一旦我们先启动主设备程序,即使我们随后启动从设备,主设备将被挂起。这种方法会丢失前面几个消息,但是你可以在不同的时刻启动主设备和从设备的程序而没有被挂起的风险。

图11-3 主设备程序


图11-4 从设备程序
直接命令
还有另外一个很酷的关于蓝牙通信功能:主设备可以直接控制从设备。
在下面的例子中,主设备直接给从设备发送命令来播放声音和移动电机,它不需要从设备程序,因为是从设备NXT的硬件直接用来接收和管理信息!

图11-5 蓝牙通讯程序

小结
在本章中,我们学习了在机器人之间使用蓝牙通信的一些基本概念:连接两个NXT,发送和接收字符串,数字和等待发送确认信号。当需要一个安全通信协议时,这最后一个点是非常重要的。
作为特别的特征,你也学会了如何直接给从设备智能积木块发送命令。
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-5-6 19:51:22 | 显示全部楼层
本帖最后由 James.Yang 于 2013-5-7 18:27 编辑

第十一章 机器人之间的通信
如果你拥有一个以上的NXT,这一章就是为你而设(虽然你仍然可以通过单台NXT与PC进行数据通信)。机器人可以通过蓝牙无线技术互相通信:你可以使多台机器人协作(或相互争斗),你可以使用两台NXT建立一个大型的复杂的机器人,这样你可以使用6个电机和8个传感器。
对良好的老式RCX,这很简单:它发出红外线消息,周围所有的机器人都能接收。
对于NXT,这将是一个完全不同的方式!首先,你必须通过智能积木块上的蓝牙菜单来连接两个或更多NXT(或NXT与PC连接),只有这样,你才可以将消息发送到连接的设备。
发起连接的NXT被称为主机,通过通道1,2,3最多可以连接3个从设备。从设备总是将主设备连接到通道0。你可以发送消息到10个可用邮箱。
主-从设备通讯
举两个程序例子,一个为主设备,一个为从设备。这些基本的程序将教你如何通过两个NXT无线网络来管理快速连续的字符串消息流。
主程序首先通过BluetoothStatus(conn)函数来检查从设备是否正确连接在通道1上(BT_CONN常数),然后通过SendRemoteString(conn,queue,string)生成并发送以M打头的递增数字串消息,而通过ReceiveRemoteString(queue,clear,string)从从设备接收消息并显示数据。

图11-1 主-从设备通讯
从设备的程序非常相似,只不过使用SendResponseString(queue,string),替代SendRemoteString,因为从设备只可以给它的主设备——通道0——发送信息。

图11-2 从-主设备通讯

你可能注意到,中止其中一个程序,另一个程序将继续发送递增数字串的消息,而并不知道它所有发出的消息都将丢失,因为没有程序在侦听另一个程序。为了避免这个问题,我们可以规划一个更好的协议来相互确认消息的发送。
发送确认号码
下面再举一些例程:这次主设备用SendRemoteNumber(conn,queue,number)来发送数字并等待从设备进行确认(ack)(在until循环内,我们可以看到有ReceiveRemoteString),只有当从设备监听到并发送确认信号后,主设备才接着发送下一条消息。从设备使用ReceiveRemoteNumber(queue,clear,number)简单接收数据并通过SendResponseNumber发送确认信号。你的主从程序必须有共同的确认码,在这些程序中,我选择了十六进制数0xFF。
主设备发送一些随机数,并等待从设备确认,每当收到一个正确的确认码,确认(ack)变量必须被清除,否则,主设备将在没有新确认码下继续发送,因为确认变量成了脏变量。
从设备持续检查邮箱,如果它不为空,显示读取的数值,并给主设备发送一个确认信号。在程序开头,我在没有读取信息情况下直接发送确认信号以防阻塞主设备,事实上,如查没有这一技巧,一旦我们先启动主设备程序,即使我们随后启动从设备,主设备将被挂起。这种方法会丢失前面几个消息,但是你可以在不同的时刻启动主设备和从设备的程序而没有被挂起的风险。

图11-3 主设备程序


图11-4 从设备程序
直接命令
还有另外一个很酷的关于蓝牙通信功能:主设备可以直接控制从设备。
在下面的例子中,主设备直接给从设备发送命令来播放声音和移动电机,它不需要从设备程序,因为是从设备NXT的硬件直接用来接收和管理信息!

图11-5 蓝牙通讯程序

小结
在本章中,我们学习了在机器人之间使用蓝牙通信的一些基本概念:连接两个NXT,发送和接收字符串,数字和等待发送确认信号。当需要一个安全通信协议时,这最后一个点是非常重要的。
作为特别的特征,你也学会了如何直接给从设备智能积木块发送命令。
图11-1.JPG
图11-2.JPG
图11-3.JPG
图11-4.JPG
图11-5.JPG
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复 1 0

使用道具 举报

 楼主| 发表于 2013-5-11 20:05:07 | 显示全部楼层
第十二章 更多命令
NXC中有很多其它的命令。在本章中,我们将讨论三种类型:使用计时器,控制显示命令,和使用NXT文件系统。
计时器
NXT有一个持续运行的计时器。该计时器以1/1000秒为增量。你可以使用CurrentTick()来得到计时器的当前值。下面是使用计时器的一个例子。程序让机器人以随机方式运动10秒钟。

图12-1 计时器的简单例子

与第四章中完成相同任务的程序相比较,使用计时器的程序是非常简单。
计时器作为wait()命令的替代命令是非常有用的。你可以通过复位计时器,让机器人休眠一段时间,然后等待,直到计时器到达设定的值。但你也可以在等待时对其他事件(如来自传感器)作出反应。下面这个简单的程序就是这样一个例子。它让机器人运动,直到过去10秒钟,或者触摸传感器碰到物品。

图12-2 计时器的又一简单例子

别忘了,如同等待命令一样,计时器也是以1/1000秒为刻度工作的。
点阵显示
NXT智能积木块具有一个分辨率为100x64像素的黑白点阵显示屏。有很多API函数可以用来绘制文本字符串,数字,点,线,矩形,圆,甚至是位图图像(.ric文件)。下面的例子将涵盖所有这些情况。像素(0,0)位于左下角。

图12-3 显示程序

所有这些功能是相当显而易见的,但我还将对其参数作些详细介绍。
ClearScreen()清除屏幕;
NumOut(X,Y,number)可以让你在指定坐标输出数字;
TextOut(x,y,string)工作原理如上,但输出的是文本字符串;
GraphicOut(x,y,filename)显示位图.ric文件;
CircleOut(x,y,radius)以指定坐标及半径画圆;
LINEOUT(x1,y1,x2,y2)从点(x1,y1)到(x2,y2)绘制一条直线;
PointOut(x,y)在屏幕上指定坐标画一个点;
RectOut(x,y,width,height)以(x,y)为左顶点按指定尺寸绘制一个矩形;
ResetScreen()复位屏幕。
文件系统
NXT可以读写存储在闪存内的文件。因此你可以保存传感器数据记录或者在程序执行过程中读取数据。文件的数量及大小的唯一限制是闪存的大小。NXT API函数可以让你管理文件(创建,重命名,删除,查找),让你可以读取和写入文本字符串,数字和单个字节。
下一个例子中,我们将看到如何创建一个文件,写入字符串并将其重命名。

图12-4 文件操作程序

首先,程序删除我们将要使用的同名文件:这不是一个好习惯(我们应该检查文件是否存在,手动删除它,或者自动为我们的工作文件选择另一个名字),但在我们的简单程序中没有问题。通过CreateFile(“Danny.txt”,512,fileHandle)创建了我们的文件,并指定了文件名称,大小以及NXT硬件为本身用途而写入一些数据的文件句柄。
然后建立字符串,并通过WriteLnString(fileHandle,string,bytesWritten)加上回车写入文件,其中所有的参数必须是变量。最后,关闭文件并重命名。记住:在开始另一个操作之前必须关闭文件,因此,如果你创建了一个文件,你可以写入文件,如果你想读取文件,你必须先关闭它,然后通过OpenFileRead()打开。要删除/重命名文件,你必须先关闭它。
要想看到结果,打开BricxCC->工具->NXT资源管理器,将DannySays.txt文件上传到电脑,并进行查看。现在进入下一个例子!我们将创建一个ASCII字符表。

图12-5 创建ASCII字符表
程序很简单,它创建了一个文件,如果没有错误发生,它将数字从0到255(先转换为字符串)通过WriteBytes(handle, s, slen)写入文件,这是不用回车写入字符串的另一种方式;然后通过WriteLn(handle, value)写入数字本身,并追加一个回车符。你可以像上述方法将其上传到电脑,然后用用文本编辑器(如Windows记事本)打开ASCII.txt来查看结果,解释如下:作为字符串写入的文本是以人们可读的方式显示,而作为十六进数值写入的数据是以ASCII代码解析并显示。
还有两个重要的函数要讨论:ReadLnString从文件读取字符串和ReadLn读取数字。
首先对第一个函数举个例子:主任务调用CreateRandomFile子程序,该子程序创建一个文件,写入随机数(字符串形式写入),在这个例子中,你可以注释掉这行而使用手工创建的文本文件代替。
然后主任务调用ReadLnString函数打开这个文件进行读取,一次读取一行,直到文件结束,并显示文本。
在CreateRandomFile子程序中产生了预定义数量的一些随机数,将它们转换为字符串,并写入文件。
ReadLnString函数接受一个句柄及字符串变量作为参数,调用结束后,字符串组成一行文本,函数返回一个错误代码,告诉我们是否已经到达文件结尾。

图12-6 ReadLnString程序
最后一个程序,我将告诉你如何从一个文件中读取数字。
在这里我还想给你介绍关于条件编译的一个小例子。在代码的开头,有一个定义不是用于定义宏也不是用于定义别名:我们只简单地定义了一个INT。
这就是哪个预处理语句:
#ifdef INT
…Code…
#endif
这就简单地告诉编译器如果程序中定义了INT,则编译上述定义行之间的语句。因此,如果我们定义了INT,就编译第一对定义行里面的主任务,如果我们定义了LONG,而不是INT,就编译第二个版本的主任务。
这个方法向我们展示了如何在同一个程序中通过调用同一个函数ReadLn(handle,val)从文件中读取int(16位)和long(32位)类型数据。
如同前面一样,这个函数接受一个文件句柄和一个数字变量作为参数,结束时返回一个错误代码。
如果传递的变量声明为int类型,该函数将从文件中读取2个字节,如果该变量是long类型,将读取4个字节。布尔变量可以以同样的方式写入和读取。

图12-7 条件编译程序
小结
在这最后一章中,介绍了NXT的一些高级功能:高分辨率定时器,点阵显示和文件系统。
图12-1.JPG
图12-2.JPG
图12-3.JPG
图12-4.JPG
图12-5.JPG
图12-6.JPG
图12-7.JPG
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2013-5-11 21:12:58 | 显示全部楼层
谢谢lz的奉献精神
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2013-5-13 19:59:12 | 显示全部楼层
Thank you for your hard work
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-5-17 20:08:36 | 显示全部楼层
第十三章 结束语
如果你通过本教程有了自己的理解,那么你现在就是NXC专家了。如果你还没有达到这一点,那么你还需要自己多多练习。随着设计和编程创造力的提升,你可以使乐高机器人做出令人难以置信的事情。
本教程并没有涵盖BricxCC所有方面的内容。建议你在学习每章时都要参阅NXC指南。此外,NXC仍处于开发阶段,将来的版本可能还会包含额外的功能。在本教程中,没有涉及许多编程概念。特别是,我们并没有涉及机器人学习行为或人工智能的其它内容。
当然也可以直接让PC驱动一个Lego机器人。这需要你用如C++,Visual Basic,Java或Delphi语言来编写一个程序。也可以让这样的程序在NXT上与NXC程序一起运行。这样的组合功能是非常强大的。如果你对机器人的这种编程方式感兴趣,最好的开始是从LEGO MINDSTORMS网站的NXTreme部分下载SDK镜像和开放源码文件。
http://mindstorms.lego.com/Overview/NXTreme.aspx
该网站是补充信息的最佳来源。其他一些重要来源是LUGNET,LEGO用户群网络(非官方):
http://www.lugnet.com/robotics/nxt
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2013-5-22 19:10:20 | 显示全部楼层
期待pdf版
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

 楼主| 发表于 2013-5-22 20:14:39 | 显示全部楼层
本帖最后由 James.Yang 于 2013-5-22 20:18 编辑

完整的PDF文档

NXC简明教程.pdf

2.25 MB, 下载次数: 5063

完整的PDF文档

如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复 2 0

使用道具 举报

发表于 2013-5-23 17:20:27 | 显示全部楼层
非常感谢,牛人,佩服佩服
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

发表于 2013-5-30 16:31:06 | 显示全部楼层
我希望有:
关于NXC的全部的函数的分类中文说明........

(有点过份,但真的很有用啊,那一堆E文,看得是晕那!)
如果您觉得我的帖子对您有用,请不吝给我一个“赞”!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|中文乐高 ( 桂ICP备13001575号-7 )

GMT+8, 2024-3-29 07:47 , Processed in 0.879534 second(s), 18 queries .

Powered by Discuz! X3.5

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表