• 沒有找到結果。

JC 程序的高级编程

在文檔中 目 录 第 1 章 (頁 56-61)

第 4 章 能力风暴编程

4.5 JC 程序的高级编程

}

这个例子实现了跟随前方物体。能力风暴可以跟随前方移动的人或物;如果撞上前方的 物体,就停一停;如果前方红外系统探测范围内没有物体,它就停下来。可以修改上面的程 序,让能力风暴避开障碍物。给一个能力风暴下载避让程序,其他的能力风暴下载跟踪程序,

在适当的条件下能看到,能力风暴一个跟着一个排成长龙,鱼贯前进。

光敏的使用和红外系统类似,所不同的是光敏只能感知左右两侧的明暗,和距离没有直 接关系。调用“photo(l); photo(2);”就能返回两侧光敏的测量值。

要用好能力风暴传感器,需要对测量、采样原理有所了解。通常在使用传感器测量之前 都有个标定过程,设置测量值的参考点。能力风暴在出厂前,已经对所有的传感器进行了检 测,但是器件偏差和环境干扰是不可避免的。比如可能会出现左右光敏对同样光强的测量值 不一样,或采样出现异常值。所以在编程中,使用一些偏移量校正、去除测量噪声和避免误 触发的方法还是很有用的。

4.5 JC 程序的高级编程

JC 支持多任务。多任务允许能力风暴同时做多件事情,如检测光源的同时避开障碍。

在 JC 中实现多任务是很简单的,只要调用 start_process(),任何一个函数都能作为一个 进程来运行。在 JC 中进程的内存空间不是独立的,所有的进程共用一个内存空间,因此全 局变量在任何进程里都可以访问。

4.5.1

第一个多进程程序

下面我们把第四节“台球”程序改成多进程的程序。

int bill_trans=0;

int bill_rot=0;

void billiards () {

int bmpr=0;

while(1) /*无限循环检测*/

{

bmpr=bumper(); /*检测碰撞传感器*/

if(bmpr!=0) {

if(bmpr==0b0011) /*正前方发生碰撞*/

{

bill_trans=-80; /*后退*/

bill_rot=0;

}

else if(bmpr==0b1100) /*正后方发生碰撞*/

{

bill_trans=80; /*前进*/

bill_rot=0;

}

else if(bmpr & 0b0101) /*左侧发生碰撞*/

{

bill_trans=0;

bill_rot=-80;

wait(0.5); /*顺时针转一个角度*/

bill_trans=80; /*前进*/

bill_rot=0;

}

else if(bmpr & 0b1010) /*右侧发生碰撞*/

{

bill_trans=0;

bill_rot=80;

wait(0.5); /*逆时针转一个角度*/

bill_trans=80; /*前进*/

bill_rot=0;

} } }

}

void billiards_drive() {

while(1)

drive(bill_trans,bill_rot); /*驱动电机*/

}

void main() {

start_process(billiards_drive()); /*创建电机驱动进程*/

start_process(billiards()); /*创建碰撞处理进程*/

}

“台球”改成多进程后,运行的效果没变,但结构已经完全不一样了。电机驱动进程 billiards_drive()专门设置电机速度,碰撞处理进程 billiards()判断碰撞并改变电机速 度。两个进程之间通过全局变量 bill_trans 和 bill_rot 进行通讯。能力风暴的操作系统自 动调度两个进程,给它们分配时间片。从执行效果来讲,就相当于这两个进程并列运行。这 样的结构非常方便增加新的进程,同时处理更多的外部信息。

4.5.2

添加一个新进程

我们给前面的程序增加一个红外避障进程,改变它的行为,而其它部分不需要做大的变 动。改动后的程序如下。

int bill_trans=0;

int bill_rot=0;

int bmpr=0;

int forward=0;

int running=0; /*能力风暴初始值处于静止状态*/

void billiards () {

while(1) /*无限循环检测*/

{

bmpr=bumper(); /*检测碰撞传感器*/

if(bmpr!=0)

{if(bmpr==0b0011) /*正前方发生碰撞*/

{forward=0;

bill_trans=-80; /*后退*/

bill_rot=0;

}

else if(bmpr==0b1100) /*正后方发生碰撞*/

{forward=1;

bill_trans=80; /*前进*/

bill_rot=0;

}

else if(bmpr & 0b0101) /*左侧发生碰撞*/

{bill_trans=0;

bill_rot=-80;

wait(0.5); /*顺时针转一个角度*/

forward=1;

bill_trans=80; /*前进*/

bill_rot=0;

}

else if(bmpr & 0b1010) /*右侧发生碰撞*/

{bill_trans=0;

bill_rot=80;

wait(0.5); /*逆时针转一个角度*/

forward=1;

bill_trans=80; /*前进*/

bill_rot=0;

}}

} }

void billiards_ir() {

int ir;

while(1) {

if(running) /*能力风暴没有开始运动,不检测障碍*/

{ ir=ir_detector(); /*检测红外传感器*/

if(bmpr==0 && forward) /*后退或发生碰撞时,不避障*/

{

if(ir==2) /*右侧有障碍,向左绕*/

{ bill_trans=20;

bill_rot=80; /*逆时针转*/

}

else if(ir==1) /*左侧有障碍,向右绕*/

{ bill_trans=20;

bill_rot=-80; /*顺时针转*/

}

else if(ir==0) /*前方没有障碍,恢复直行*/

{ bill_trans=80;

bill_rot=0;

}}

wait(0.1);

}}

}

void billiards_drive() {

while(1)

{ running = bill_trans; /*能力风暴正在运动*/

drive(bill_trans,bill_rot); /*驱动电机*/

} }

void main() {

start_process(billiards_drive()); /*创建电机驱动进程*/

start_process(billiards_ir()); /*创建避障进程*/

start_process(billiards()); /*创建碰撞处理进程*/

}

改动以后的程序增加了避开侧面障碍物的行为。比较一下,增加的代码除了红外避障进 程外,就是用于进程之间的通讯。进程间的通讯和同步是多进程编程的难点,不解决好这个 问题,多进程程序可能会产生一些奇怪的行为。在这个程序里,由于碰撞处理进程和红外避 障进程都要修改设置电机速度的两个全局变量(bill_trans,bill_rot),这是进程间发生冲 突的根源。如果不加以限制,两个进程同时修改电机速度,必然会出现一片混乱,能力风暴 下一步的运动方向将无法预知。

本程序中把 bmpr 改为全局变量,通过 bmpr 来划分两个进程生效的时间。即发生碰撞时,

只有碰撞处理进程可以修改电机速度;在其他时间里碰撞处理进程只是在不断检测碰撞传感 器,只有红外避障进程才有可能修改电机速度。我们可以看到,在本程序里碰撞处理进程的 优先级高于红外避障进程。增加的另两个全局变量是出于红外避障行为逻辑的需要。全局变 量 running 是能力风暴开始运动的标志,红外避障进程要等待这一事件发生后才能起作用。

forward 反映能力风暴当前运动方向,用于避免红外避障进程在后退时候处理前方障碍。

在文檔中 目 录 第 1 章 (頁 56-61)