《仿人机器人原理与实战》一1.4 反射弧实验进阶-阿里云开发者社区

开发者社区> 华章出版社> 正文
登录阅读全文

《仿人机器人原理与实战》一1.4 反射弧实验进阶

简介: 本节书摘来华章计算机《仿人机器人原理与实战》一书中的第1章 ,第1.4节,作者布莱恩·伯杰伦(Bryan Bergeron) 托马斯B. 塔尔博特(Thomas B. Talbot) 王伟 魏洪兴 刘斐 译, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

本节书摘来华章计算机《仿人机器人原理与实战》一书中的第1章 ,第1.4节,作者布莱恩·伯杰伦(Bryan Bergeron) 托马斯B. 塔尔博特(Thomas B. Talbot) 王伟 魏洪兴 刘斐 译, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

1.4 反射弧实验进阶

在仿人机器人的设计中,这种简单的反射弧模拟装置不仅功能齐全而且十分有用。同人类的反射一样,直至反射被触发,舵机才正常运转。不过,你可以将程序稍作改进,以便提供更多有实用价值的功能。按照如下顺序,我们将这些功能添加到模拟器的硬件和代码库中。

1.4.1 反射方向

第一个改进是以编程方式定义反射方向。如果把开关S1安装在舵机摇臂上,那么反射可以使按钮的运动方向朝向或躲避撞击物体。如果反射方向不能满足设计要求,那么你可以移动开关,或者减小位置变量的值至0。以下是需要替换的递增代码语句:
q1

以下语句可以实现position变量的递减:
q2

我们假设把开关S1安装在双足仿人机器人的脚趾位置。总的来说,当某物体激活开关S1后,适当的反射行为应是将脚从物体上挪开。但在你觉得大功告成之前,想想你自己碰到脚趾时的正常反应。然而,在特殊的情景中,有一些自然反射可能并不合时宜,所以你需要通过程序控制来改变反射弧方向。让我们在程序中引入方向变量reflectDirection和子程序makeReflex,如清单1-2所示。
清单1-2 控制反射方向的Arduino代码
q3
q4
q5

在主循环中,用子程序makeReflex替换了舵机角度递增代码。只要手动或由程序自动改变reflectDirection变量的值,舵机便能相应地转换反射方向(注意:变量reflectDirection的取值为0或1)。别忘了,你可以轻松自如地从网络上获取相关程序代码。

1.4.2 绝对不应期

在这一点上,我们的反射弧模拟器本身就存在一段绝对不应期,即开关S1无响应的时段,这是由于舵机和机械附件的机电设计原理导致的。因为不存在完全相同的两个舵机,所以最好定义一段绝对不应期,这样通过设置绝对不应期能够从程序上消除不同舵机的响应差异。当涉及多肢体甚至更多舵机的时候,这种协调能力会显得更加重要。
现在,我们定义一个常数absoluteRefractory来表示绝对不应期,以毫秒为单位,在此期间开关S1不能触发任何反射活动。但是在旋转电位器旋钮P1时,舵机可以正常运转。在反射活动完成之后,我们可以通过调用delay()函数设定一段绝对不应期,但在清单1-3中,我们列出了一种更好的解决途径。
清单1-3 带绝对不应期的简单反射弧的Arduino代码
q6
q7
q8
q9

因为在绝对不应期内我们想禁止反射活动的发生,所以我们需要估算这段时间。对于这一点,我们可以通过调用millis()函数实现,该函数会返回一个以毫秒为单位的数值,描述从上次通电后Arduino的开机时间。变量previousMillis和currentMillis可以用来存储millis()函数在不同程序段的返回值,从而实现了时间间隔的测量。
虽然这个方法比调用delay()函数更复杂,但好处是在设置、检查、复位的时间内并没有让处理器休眠。从本质上来看,delay()函数暂停了Arduino微控制器的运行,在此期间,机器人如同“盲人”一样对传感器没有响应。

1.4.3 相对不应期

从上一次反射完成后的一段时间起,产生反射的刺激会随时间逐渐减弱,因此,增设相对不应期不仅增加了反射活动的真实感,也是添加新硬件的最好理由。确切地说,我们要用一个模拟传感器取代开关S1,对于不同程度的刺激,模拟传感器都可以做出相应的响应。
为了找到最简单的解决办法,我们选用Sparkfun 生产的力敏电阻FSR1。无外力时,FSR1的阻值最大可达1MΩ,若用手指轻触,阻值最小为1kΩ。力敏电阻比较敏感(100g),所以能准确测定刺激的强度,而且价格适中。用自粘性橡胶带来固定力敏电阻是小菜一碟的事情。力敏电阻的唯一缺点是引线。不过没有焊接那么复杂。如果你手头有绕线工具或者Grove接线端子,就可以把传感器和Arduino微控制器连接起来。图1-7是力敏电阻的特写。
这种力敏电阻并没有什么特别,可以随便用你手头的东西替代它,从有复位弹簧的线性电位器到一对嵌入在1英尺导电泡沫管中的裸露铜线都可以。有一点需要预先声明,传感器对于刺激应该比较敏感。如果你选择的传感器只有在铁锤的敲击下来能触发,那我们的整个实验可能都无法正常运作了。
还有一种选择是用压电拾音器代替电阻式传感器。尽管对手指轻触产生的压力十分敏感,但压电拾音器的输出是非线性的,加大了区别刺激强度的难度。你也可以用应变仪准确测量压力读数,但是准确度的提高意味着可能付出相当大的代价。目前,我们仍然选择用力敏电阻。
按照图1-8所示连接新添加的零件。首先,我们增设两个零件—10kΩ的电阻R1和力敏电阻FSR1,构成分压回路。传感器一端连接5V直流电源,另一端连接引脚A1和电阻R1。而电阻R1的另一端接地。

如果无外力作用于力敏电阻,理论上10kΩ的电阻R1几乎没有分得电压。现在用你的手指轻触电阻,力敏电阻阻值一下从1MΩ以上降至约2kΩ,因此电阻R1分得了大部分电压。回想分压方程,一对电阻中,其中一个电阻的压降与其电阻值除以两个电阻值总和成比例。在这个实验中,电阻R1的压降(VR1)等于总电压(5V)乘以R1的阻值再除以两个电阻值(R1+FSR1)的总和:

VR1 = 5V × R1/(R1+FSR1)

所以,当FSR1无负荷时,可得

VR1 = 5V × 10 000/(10 000+1 000 000) = 0.05V

当FSR1满负荷时,可得

VR1 = 5V × 10 000/(10 000+1 000) = 4.55V

如清单1-4所示,这段代码添加了一段相对不应期。注意,程序中加入了一个新的复位子程序。
清单1-4 带绝对不应期和相对不应期的简单反射弧模拟器的Arduino代码
q13
q14
q15
q16
q17

如下面这一段代码所示,如果系统处于绝对不应期,程序就不能接收力传感器的信号,更不用说计算不应期的时间。

一旦绝对不应期结束,设置相对不应期的代码会紧跟着运行。在程序列表中,变量sensorRange 定义了力传感器的范围,即相对不应期。
如图1-9所示,相对不应期内触发电平以指数形式减弱,我们可以用斜直线来逼近该曲线。直线方程是y=mx+b,其中x、y为轴线,m为直线的斜率,而b是常数。这个程序中,我们定义斜率为0.25,常数b的值是1000,这些都由变量sensorRange来表示。


9


相关代码包括首次确定最小触发电平值triggerVar,它是有关时间和系统噪声级noiseLevel的函数。尽管在通常意义下是没有噪声的,但是变量noiseLevel可以很方便地逼近反射在最小触发条件下的波动。
此外,因为按周期对力敏电阻做采样,返回字符串的峰值往往位于中间位置,所以我们利用max函数作为峰值检测算法。一旦确定最小触发电平的值,我们便可以很轻松地把它与力敏电阻返回的信号峰值进行比较,再储存到变量FSRMaxVal中。
为了观察处于相对不应期时系统的响应,我们可以一只手旋转电位器旋钮P1,另一只手压在力敏电阻上,尝试触发反射活动。如果需要在上一个反射完成后的几毫秒内立刻触发下一个反射,那么你必须重压FSR1,否则需要等待几毫秒或几秒,再轻触力敏电阻即可。如果想验证这一点,不妨从舵机摇臂上卸下力敏电阻,并将其安装在你的桌子上。

1.4.4 大脑冻结

这个名词让我们想到大脑对反射弧的一些负面影响。但是,当在特定环境下反射是一件坏事的时候,大脑冻结对仿人机器人可能非常重要。想象一个攻击型机器人正隐藏在茂密的雨林中,但是一些动物正在啃它的脚踝,此时,他最好站着不动,否则,冒险杀死这些害虫就可能被敌人发现。现在,我们再次使用开关S1模拟大脑皮层抑制,并且同样沿用图1-10中的电路连接引脚。

10


,S1抑制反射在构建绝对和相对抑制工作的时候,抑制反射弧的相关代码如清单1-5所示。我们要定义一个关于S1激活状态的新变量,即globalInhibition,并且通过它来增加噪声水平变量noiseLevel的值,只有当信号电平达到noiseLevel的值时才能激发反射弧。
清单1-5 反射弧的反射抑制的Arduino代码
q18
q19
q20
q21
q22

当开关S1按下时,引脚inhibitionPin D7接地,noiseLevel的值升到250,从而大幅提高了触发makeReflex()函数所需的压力传感器最小值。
我们用电位器代替瞬时接触开关S1,使得模拟过程变得更加真实。但你很快就会发现:由于相对不应期的交叉作用,我们很难调节系统,并且对于中等量抑制,系统的调节量变小。
对于人类而言,我们时常会抑制某些特定的反射。假设你的仿人机器人正漫步在庭院里,而“脚趾”传感器一直被脚底下的长草触发,那么在地势变得平坦之前,相关反射应该被抑制。

1.4.5 肾上腺素冲动

在生死存亡的紧要关头,仿人机器人可能不得不打破正常的操作限制以便立即实施救援。假设你的仿人机器人只有30秒的时间可用于到达四旋翼救援无人机,并且需要先拔除限位装置才能冲向它。我们把Arduino的数字引脚D6与另外一个开关S2相连接,模拟这个情景中肾上腺素的冲动,如图1-11所示。

11


考虑到肾上腺素的总体效果与大脑皮层抑制完全相反,我们决定使用类似的代码结构,降低而不是增加有效的噪声水平,如清单1-6中所示。
清单1-6 对反射弧增加了肾上腺素冲动的Arduino代码
q24
q25
q26
q27

事实上,正如inhibitionState和globalInhibition是模拟反射抑制的变量一样,excitationState和globalExcitation是模拟肾上腺素的变量。唯一的差别是,globalExcitation会降低noiseLevel的值,因此降低阈值有利于激活反射。虽然你能根据要求无限制地改变噪声水平的值,但是必须将其限制在一定水平之上。如果把这个值降低到接近0,你的仿人机器人就会特别“紧张”,一个轻微的振动都很有可能激活一系列反射弧,而这样敏感的性格其实并不适用于仿人机器人。
注意,我们用简单的代数求和公式将抑制与激励信号综合,最终得到触发电平的值,计算如下:

q28

你也可以把抑制与激励的值加权实现传感器融合,从而得到触发电平的值。通过这个算法,你可以让抑制信号的权值是激励信号的三倍或是相反,只需要增加一个常数乘子。或者你可以跟踪先前的计算值并将其代入预测算法中。简而言之,不要简单地将传感器值相加,在实验中采用传感器读数融合和组合的方法是为了实现你想要的机器人行为。
如同之前模拟反射抑制的实验一样,可以用开关S2代替电位器,这么做可以感觉到传感器输入与激励和抑制效果互相较量的交互性。在协调多个传感器和舵机共同工作时,用电位器操控含抑制与激励的反射弧可以节约很多时间。
例如,仿人机器人的一只胳膊上也许拥有一个比较迟钝的舵机,而另一只胳膊上一起工作的舵机设置的不应期是无效的。我们不用在编辑器上重复微调变量然后编译,而是直接在运行过程中调整电位器P1的值并观察效果。一旦最优值确定,便可以简单地清除相关元件和代码。
而且,你可以通过编写程序改变由开关S1、S2触发的抑制和激励的相对水平。正如之前所提及的,切换开关比读取一对电位器值的工作量要小得多。当你了解了各类操作参数的不同之处时,开关就会发挥很大作用。例如,你可能会有两个电池包,一个是标准型号,另外一个是加长版(很重),此时,开关能很好地修改反射的预置值,以此来补偿额外的重量和重心的变化。

1.4.6 添加舵机

现在你已经具备相关基础知识,我们可以在系统中添加更多执行器(即舵机)。让我们把第二个舵机添加到系统中,如图1-12所示,用它来模拟第二块肌肉或者同一块肌肉上的第二束肌肉纤维。


q29

第二个舵机的相关代码如清单1-7所示。在这个例子中,第二舵机是第一个舵机动作的镜像。此外,我们还需要再增加一个电位器和相关代码。
清单1-7 支持第二个舵机的Arduino程序
q30
q31
q32
q33
q34

关键是通过声明myservo2语句首先创建第二个舵机对象,然后在setup()子函数中将第二个舵机与引脚号关联起来。在makeReflex()子程序中调用write函数可以使两个舵机同步协调运动。
你可以通过添加附件控制或代码来指定不应期和抑制期的方式,以及模拟肾上腺素冲动的方式来修改第二个舵机的响应。作为练习,考虑如何抑制一个舵机同时保持另一个舵机激活,即模拟肱二头肌和肱三头肌或肱四头肌和肌腱的反射。这时,你将会遇到一些困难,即Arduino上可用于传感器的模拟端口有限且没有端口复用等补救措施。

1.4.7 其他控制器

如果Arduino Uno微控制器负载过重,你可以求助于专用舵机控制器,它能腾出端口并处理传感器和其他任务。此外,专用舵机控制器允许设定PWM脉冲频率和脉冲宽度,为每个舵机指定速度、加速度以及启动位置,且所有命令都是通过标准的串行连接。你也可以像反射那样编排若干序列,从Arduino发出单个串行命令以实现触发。
Pololu生产的Maestro舵机控制器拥有丰富的功能集,形式多样,可用于自由构架的控制程序。Parallax生产的螺旋桨式控制器是完全可编程的,并且带有16个舵机的硬件资源和连接端口。这些控制器或其他专用舵机控制器的缺点是成本过高—大约和一个Arduino微控制器的价格一样。
Parallax也提供了一个介于两者之间的选择,它不算是一个控制器,但也可以为Arduino腾出运算资源。Parallax的ServoPAL模块是一个廉价的微型组件,插在舵机引脚和电线之间。它只是简单地重复从Arduino中接收的前一组PWM脉冲,整个过程无需编程。

1.4.8 其他传感器

在以上实例电路中,任何有数值输出功能的传感器通常都可以替代瞬时接触开关,但往往需要重新编写少量代码。例如,水银倾斜开关、磁簧开关、光敏晶体管都可以连接到一个数字输入引脚,而不需要重复编程。但其他数字输出传感器都需要适度编程,例如红外(IR)和超声波测距仪。
使用数字传感器最大的优势是Arduino有大量数字引脚,和大多数微控制器一样。然而,当事情变得复杂,例如有一对以上的舵机和传感器时,就需要把传感器、舵机、微控制器的电源和信号线隔离。用不同的独立电源供应舵机和传感器,通过一种光学隔离器(例如4N35)把传感器的信号和微控制器连接起来。
与数字传感器相比,模拟传感器往往有更大的灵活性。然而,他们通常需要更多的系统开销,当然也需要占用其中一个本来就很少的模拟量输入端口。在反射弧背景下,热传感器、压力传感器、霍尔效应传感器和声音传感器都很值得研究。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享: