一种声光电磁网结合的鲁布·戈德堡机械的设计与实现

2012/07/31 | 23:01 | 分类:电子与无线电 | 标签: | 6,532次阅读

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
(林健,BH1NAF)

概述

  传统鲁布·戈德堡机械往往以多种物理传动装置连接构成,通过机械连锁反应实现无意义的功能,视觉冲击力和趣味性强。但其设计实现受制于空间和材料、部署与执行稳定性低、实验和调试成本高。本文提出一种以电子技术为主的,声光电磁网结合的鲁布·戈德堡机械设计思路。相比传统设计,基于电子技术的设计具有执行速度快、空间可扩展性强、受物理环境干扰小、便于重做和调试等优势。此外,作者期望使鲁布·戈德堡机械具备有意义的功能,兼顾趣味性和实用性。基于此设计,本文给出了一套原型系统,通过模拟电路、微控制器、单板机、微型计算机、无线电与红外线收发信机以及网络终设备的连接与交互,实现了一种具有声光反馈、能够自动归档的分布式CW电键练习装置。实验验证了此类设计的可行性与应用优势。

  (以下省略原理与模型设计部分)

原型系统

  图0给出了基于电子技术的鲁布·戈德堡机械原型系统的执行流程。下文通过展示原型系统实现效果,对此流程进行简述。

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图0 基于电子技术的鲁布·戈德堡机械原型系统的执行流程

  CW电键作为开关,控制左侧回路电流通断。电流接通时,电磁铁产生磁场,使得右侧回路中的干簧管导通,输出控制电平。右侧回路中带有一个发光二极管,作为视觉反馈。

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图1 接口电路

  左侧Arduino 1检测到控制电平后,通过数字I/O点亮发光二极管,并设置少量延时,防止抖动。右侧Arduino 2以光敏电阻作为电平控制开关,在光照达到一定强度后,通过数字I/O输出1000Hz的方波信号,并将该信号作为调频发射机的音频输入。调频发射机将信号调制之后,在100.0MHz上广播。

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图2 Arduino 1、Arduino 2

  调频收音机接收频率设置为100.0MHz,并将耳机输出作为红外发射机的音频输入。红外发射机将信号调制之后,以2.8MHz载波频率发射。

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图3 调频收音机

  红外收音机固定接收2.8MHz的红外载波信号,将音频信号解调之后直接播放,一方面作为听觉反馈,一方面通过计算机1(Windows系统)的麦克风输入,由计算机上运行的MultiPSK软件进行信号处理,将音频序列按Morse电码解码为字符序列,输出在屏幕上(可观察到“HELLO WORLD”序列)。同时在无线网卡上开放3122端口,以TCP报文发送字符序列。
  注意,这里可以将红外收音机的耳机输出连接到计算机的线路输入接口或麦克风接口。为消除干扰,可添加简单的滤波电路。如果使用麦克风接口,还需要考虑降低输入电平。原型系统中为体现听觉反馈特性,采用外放外录方案。

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图4 红外收音机、计算机1

  计算机2(Linux系统)同样连接无线网络,使用nc命令监听计算机1发来的TCP报文,使用tr命令将MultiPSK生成的组分隔符(\035)替换为换行符(\n),然后通过管道将字符序列重定向到本地串口ttyS0。该串口连接到Raspberry Pi的USB外接串口ttyUSB0,Raspberry Pi读取串口输出,写入命名管道mypipe。后台执行的sender脚本定时读取mypipe,将字符序列调整格式,封装为发送给Kindle Personal Documents Service的SMTP消息。借助3G路由器和3G Modem,先后通过有线网络和3G网络连接远程邮件服务器发送邮件。

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图5 计算机2、Raspberry Pi、3G路由器

  Kindle通过3G网络接收来自Personal Documents Service的推送信息。点击之后可显示定时归档的字符序列(可观察到“HELLO WORLD”序列)。
  注意:原型系统为节省Amazon美国境外3G推送服务费用,使用WiFi网络演示

一种声光电磁网结合的鲁布·戈德堡机械的设计与实现
图6 Kindle

  除最后一步基于网络服务的自动归档外,系统其他环节皆以接近光速、声速或局域网络延迟的速度执行,满足CW电键练习装置的实时性需求。

  (以下省略系统评测与相关工作部分)

结论

  本文提出的以电子技术为主的,声光电磁网结合的鲁布·戈德堡机械设计思路在一定程度上解决了此类机械设计中的稳定性、可扩展性和可调试性等问题。给出的原型系统在传统CW电键练习装置基础上增加了分布式部署、自动归档等特性,验证了这类设计的可行性,体现了趣味性和实用性。
  Arduino和Raspberry Pi提供了I2C、SPI等数字与模拟输入输出接口,在设计时可以充分发挥其能力,例如连接传感器与物理世界进行交互。此外,电话、电视与电力网络、互联网Mashup服务乃至业余卫星与短波通信等也可作为设计元素,以此增强系统的空间扩展性。本文由于器材和时间限制,未进行深入研究。

致谢

  感谢为我提供部分实验器材的同学,感谢各位耐心的读者。

为什么有的 USB 线缆不能为手机充电?

2011/07/28 | 20:54 | 分类:电子与无线电 | 标签: | 5,086次阅读

  我手头有若干移动设备附带的 USB 数缆,它们一端是标准 USB 接口,另一端是 MiniUSB 或 MicroUSB 接口。USB 线缆内部通常有 4 根线(如果算上连接到金属壳的屏蔽层,则是 5 根),其中 2 根用来供电,2 根用来传输数据。有的线缆内部只有 2 根供电线。4 根线齐全的可称为“数据线”,只有 2 根的可称为“充电线”。我的一部 Huawei 手机可以使用任何一根 USB-MiniUSB 数据线或充电线充电,也可以使用任何一根 USB-MiniUSB 数据线传输数据。但我的 MOTO Milestone 却只能使用特定的两根线缆充电或传输数据,其中一根是原装的 USB-MicroUSB 数据线,另一根是某移动硬盘附带的 USB-MiniUSB 数据线外加一个 MiniUSB-MicroUSB 转接头。使用其他线缆,手机要么没有任何反应,要么充电指示灯不断闪烁。看来,MOTO 的智能手机比 Huawei 的土手机更“挑”线。可是,“挑”线的原理是什么呢?我通过查阅标准并实验,初步找到了原因。
  查阅 USB 相关标准得知,MiniUSB 和 MicroUSB 接口比标准 USB 接口多一个 pin,即用于 OTG 功能的 pin 4(ID)。根据在 OTG 中的不同用途,pin 4 有不同的接法,可能接地,即与 pin 5 短接,也可能悬空。用万用表测试并实验,发现凡是 pin 4 接地的线缆,均不能为 Milestone 充电。这有可能是 Milestone 有意设计的。
  但我还有一根 Nokia 的 USB-MicroUSB 数据线,pin 4 悬空,却不能给 Milestone 充电,这又是为什么?是它的电阻太大了吗?测量一下,单根供电线的电阻约为 3Ω,对比测量 MOTO 原装数据线,只有 1Ω 左右。同时注意到这根 Nokia 数据线比较细,可能没有屏蔽层。测量发现两端接口的金属壳没有连通,基本可以证实猜测。
  最后测试一下不同线缆的充电电流如何。我没有直流钳表,于是想到 DIY 一个 USB 电流测试装置。如图所示,不多解释,这个装置从设计到实现用了不到一刻钟。测试表明,这根 Nokia 数据线的充电电流约为 180mA,而能正常充电的 2 根线缆均在 400mA 左右。对于 pin 4 接地的线缆,显示电流为 1-2mA,可能是 Milestone 中某些保护电路的效果?
为什么有的 USB 线缆不能为手机充电?
  然后就被某数学家说成是民科了……我明明是国家队的嘛……

玻璃硬盘拆拆看

2011/03/20 | 11:50 | 分类:IT杂谈 | 标签: | 4,174次阅读

  @Sisyphusliu 师兄从杂物堆中翻出一块坏了的 IBM Deskstar 60GXP IC35L060AVER07-0 硬盘给我研究。虽说我以前也拆过若干坏硬盘,但这一块还是有点与众不同的:它采用的是石英玻璃盘片,俗称“玻璃硬盘”。2000 年到 2002 年的 IBM 玻璃硬盘风波我有所耳闻,玻璃硬盘的性能优势使得 IBM 硬盘事业部风光一时,然而后续的发现的稳定性问题又使其一蹶不振,最终被日立收购(当然,前几天日立又被西部数据收购了)。既然有历史证物在手,就要自己动手实践一下,看看传说中的玻璃盘片和传统铝合金盘片有什么不同。
  网上有关拆解这个系列硬盘的文章和视频已经很多了[1][2],我就不再贴详图,只发两张有代表性的:

  开盖视图:
玻璃硬盘拆拆看

  大卸八块:
玻璃硬盘拆拆看

  有关这个盘片,我一开始真没敢相信它是玻璃材质的。从感观上,如同抛光电镀的金属,一点也不透光;敲击的声响也像金属一样轻脆。表面涂层刮不下来,看不到任何玻璃的迹象。不过在测试其硬度时就有点眉目了:用不锈钢小刀划盘面,只留下很不明显的痕迹。因为不锈钢的莫氏硬度大于铝而小于石英玻璃,所以判定它不是铝。进一步判定材质还可以通过延展性实验,但我一时没有找到安全的实验方法。还是王总 @Evan_65 威武,找了个支撑物一脚踩碎了盘片(危险动作切勿模仿)。这下大家看清楚了,藏在金属涂层下面的确实是透明的玻璃。后来一查,敲击盘片发出类似金属的声响正是石英玻璃区别于普通玻璃的物理特性之一。

  “磁盘碎片”:
玻璃硬盘拆拆看

  60G 版本的 60GXP 共有三个盘片,实验消耗了一个,另外两个就拿来做收藏吧,毕竟是绝版的。

  最后,让我们回放一下硬盘完全解体之前的内部工作状态:


  (也可前往新浪视频Youtube 观看)

一道 C 语言指针访存题目的引申

2009/11/08 | 13:41 | 分类:计算机科学与编程 | 标签: | 4,582次阅读

  毕业生求职的时节,非毕业生接触到各种面试、笔试题目的几率也会相应地增加。下面请看一道经典的 C 语言指针访存题目,稍有些经验的朋友应该很快可以看出这个题目考查的是字节序、内存布局等知识点。然后在大脑中略排列一下,就能够给出答案(2000000)。

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.     int a[5] = {1, 2, 3, 4, 5};
  6.     int *pa = (int)(&a) + 1;
  7.     printf("%x\n", *pa);
  8.     return 0;
  9. }

  不过,这个答案是否绝对正确,还要看题目所处的上下文了。如果题目明确说是在常见的 32 位 x86 平台上运行,那就无可厚非;但如果没有指明机器架构,那就要小心一点了,也许命题者真想考查一下求职者对非 x86 平台的了解程度呢。如果考虑机器架构,这个题目应当如何作答呢?粗想一下,我们需要考虑的是字长、字节序和对齐(alignment)访问规则。不过真要做实验看看,会发现这里面还是有一些花样的。如果没有实际经验,只凭教条加推测,很可能想不到其它平台上的一些细节之处。
  我们换用一段信息量更丰富的程序来进行后续的实验。在不同的平台上,均使用未加特殊参数的 gcc 来编译这段程序——

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5.     int x;
  6.     int a[5] = {0x11121314, 0x21222324, 0x31323334, 0x41424344, 0x51525354};
  7.     for (x = 0; x < 20; x++) {
  8.         printf("%02x ", *(char *)((int)(&a) + x));
  9.     }
  10.     printf("\n");
  11.     for (x = 0; x < 8; x++) {
  12.         printf("%08x ", *(int *)((int)(&a) + x));
  13.     }
  14.     printf("\n");
  15.     return 0;
  16. }

  在 32 位 x86 下的结果不需要多解释。

  1. uname -a
  2. Linux ubuntu 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:04:26 UTC 2009 i686 GNU/Linux
  3. ./a.out
  4. 14 13 12 11 24 23 22 21 34 33 32 31 44 43 42 41 54 53 52 51
  5. 11121314 24111213 23241112 22232411 21222324 34212223 33342122 32333421

  而在 64 位的 x86_64 下,由于 8 字节的指针被截断到了 4 字节的整型长度,故会引发段错误。同样的情况出现在 64 位的 Alpha 机器下。解决办法自然是把运算地址时的 int 修改成 long 或某种显式的 64 位类型。修改后的结果应该与 32 位 x86 一致。

  1. uname -a
  2. Linux ubuntu 2.6.24-22-generic #1 SMP Mon Nov 24 19:35:06 UTC 2008 x86_64 GNU/Linux
  3. ./a.out
  4. Segmentation fault
  1. uname -a
  2. NetBSD sdf 2.1.0_STABLE NetBSD 2.1.0_STABLE (sdf) #0: Fri Mar 30 02:24:32 UTC 2007  root@ol:/var/sys/arch/alpha/compile/sdf alpha
  3. ./a.out
  4. Memory fault (core dumped)

  有趣的是在 XScale(Intel 实现的 ARMv5)下,虽然同属 little-endian,但非对齐取数时出现了在字内按字节循环的移位的结果。查查 ARM 的官方文档,这确实是 ARMv5 的特性;而在 ARMv6 以后,非对齐访问则是完全支持的。

  1. uname -a
  2. Linux zaurus 2.4.18-rmk7-pxa3-embedix #1 Sat, 06 Aug 2005 12:22:55 +0000 armv5tel unknown
  3. ./a.out
  4. 14 13 12 11 24 23 22 21 34 33 32 31 44 43 42 41 54 53 52 51
  5. 11121314 14111213 13141112 12131411 21222324 24212223 23242122 22232421

  接下来看看 PowerPC,它是 big-endian 的代表,允许 32 位以内的非对齐访问,结果是容易理解的。有关 PowerPC 非对齐访问的一些细节可以参考这篇文章

  1. uname -a
  2. AIX aix 3 5 00C97AC04C00 powerpc unknown AIX
  3. ./a.out
  4. 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 51 52 53 54
  5. 11121314 12131421 13142122 14212223 21222324 22232431 23243132 24313233

  同样是 big-endium 的 SPARC 则不允许非对齐访问。它会对非对齐访问抛出 SIGBUS。

  1. uname -a
  2. SunOS t1000 5.10 Generic_118833-33 sun4v sparc SUNW,Sun-Fire-T1000 Solaris
  3. ./a.out
  4. 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 51 52 53 54
  5. Bus Error (core dumped)

  最后看看我们中科院计算所的龙芯(Loongson)2E,它是兼容 MIPS 架构的处理器。很多教科书告诉我们说通常的 MIPS 是不允许非对齐访问的(部分 MIPS 实现提供了非对齐访问指令,并申请了专利),但我们在龙芯下却得到了和 x86 相同的、允许非对齐访问的结果,这又是为什么呢?初步查到的原因是“(针对龙芯修改过的 Linux)内核里确实有一个异常处理函数负责处理 lw 访问非对齐地址引起的异常”。这也许是龙芯绕开 MIPS 专利的一种办法?我会向龙芯团队的同学求证一下,也希望熟悉 MIPS 或龙芯的朋友给我一个确切的答案。

  1. uname -a
  2. Linux Loongson-1 2.6.18.1lemote #1 Sat Jan 13 16:02:26 CST 2007 mips GNU/Linux
  3. ./a.out
  4. 14 13 12 11 24 23 22 21 34 33 32 31 44 43 42 41 54 53 52 51
  5. 11121314 24111213 23241112 22232411 21222324 34212223 33342122 32333421

  不过用心思考的朋友也许会发现上面一系列实验存在的一个疏漏:没有考虑编译器的影响。一方面,编译器可能对整型的字长有不同的规定(例如 Windows 下的某些编译器即使在 32 位 x86 上也会把 int 定义为 16 位);另一方面,编译器可以对不支持非对齐访问的处理器生成一定的指令序列、通过多次访存来模拟非对齐访问。我们看下面的例子:还是在 SPARC 平台上,改用 Solaris 自带的 Sun CC 来编译实验程序,这时就不会出现“Bus Error”,而会输出和 PowerPC 一样的结果。因为 SunCC 默认会使用“-xmemalign”参数来生成适当的访存指令序列。

  1. uname -a
  2. SunOS t1000 5.10 Generic_118833-33 sun4v sparc SUNW,Sun-Fire-T1000 Solaris
  3. cc data.c
  4. ./a.out
  5. 11 12 13 14 21 22 23 24 31 32 33 34 41 42 43 44 51 52 53 54
  6. 11121314 12131421 13142122 14212223 21222324 22232431 23243132 24313233

  这样看来,在不指定机器架构和编译器等上下文的情况下,要正确且完美地回答一开始的那道题目还是需要一定知识积累的。答案省略,留给大家自己求解。在面试、笔试诸如 Sun SPARC、IBM PowerPC、中科院计算所微处理器中心等部门或者做 ARM 等嵌入式开发的公司时,最好先了解清楚它们的产品常识。
  (部分实验环境来源于 Unix-Center.Net,在此致谢)

试用Windows的UNIX/POSIX子系统(SUA)

2009/05/04 | 20:07 | 分类:Windows应用 | 标签: | 7,721次阅读

  以前研究Windows的基本概念时,我就知道它有一个POSIX子系统,可以在Windows下编译运行使用了POSIX库的程序。但这一直停留在书本概念层面,直到昨天看到Jeep同学的Windows系统上安装了一个Subsystem for UNIX-based Applications时,我便决定也安装试用一下。
  有关Windows的POSIX子系统是什么、怎么用的问题,可以参考Wikipedia或Microsoft TechNet [英文][中文]上的介绍。它历经了NT时代的Microsoft POSIX subsystem、XP/2000时代的Microsoft Windows Services for UNIX (SFU)以及2003 R2/Vista/2008时代的Subsystem for UNIX-based Applications (SUA)等版本,对POSIX标准的支持日臻完善。我的系统是来自MSDNAA/IEEE的Windows Server 2008,自然要使用最新版的SUA。至于SUA和cygwin在实现机理和功能性能上有什么区别,我还没有仔细研究。但从直观感觉上,Windows原生支持的SUA是比cygwin快一点儿;按照Wikipedia上的这个说法,cygwin是对POSIX是“partial”兼容,而SFU/SUA则是“full”兼容。
  很多人安装SUA的目的并不是要向Windows移植什么重要的UNIX/Linux应用,有时候我们仅仅是为了在Windows中使用一个类UNIX的Shell以及丰富的GNU utilities,毕竟这类久经考验的命令行工具比Windows Command Prompt的那些命令好使很多。对于工作环境要求在Windows和Linux间来来回回切换的人们,也省得敲错命令。安装SUA之后,预装的Shell是C Shell和Korn Shell,还安装了包括vi、gcc在内的300多个命令行工具。同时,Windows的Path环境变量中自动添加了SUA相关目录,这样在Windows Command Prompt和Power Shell中也可以使用很多GNU utilities了。当然,UNIX Shell的内部命令是不可以在这里使用的。此外,在Power Shell中,Power Shell命令别名(如ls、cp)会优先于同名的GNU utilities调用。总之,使用SUA或cygwin这类UNIX Shell+GNU utilities的模拟环境,相比手工添加的“容错”命令或者GnuWin32这类独立命令级的移植要“真实”和顺手得多,但缺点就是体积庞大。
  为了检验SUA的能力,我拿我相对熟悉的GNU bash做了实验。从官方下载bash-4.0版源代码,在SUA的C Shell环境中解压,运行./configure通过。但在make时报错:

  1. execute_cmd.c: In function `time_command':
  2. execute_cmd.c:1145: error: storage size of `dtz' isn't known

  查看execute_cmd.c源代码,发现这句代码有注释:

  1. struct timezone dtz; /* posix doesn't define this */

  看来这个struct timezone不是POSIX标准的东西。通过上下文,我发现这里是处理time(计时)关键字的函数。于是查看configure的帮助,得知只要加一个“--disable-command-timing”参数即可禁用time关键字(这时输入time将改用/bin/time程序做计时)。再次make,execute_cmd.c通过,但又出现以下错误:

  1. getcwd.c: In function `_path_checkino':
  2. getcwd.c:80: error: `MP_RMDOT' undeclared (first use in this function)
  3. getcwd.c:80: error: (Each undeclared identifier is reported only once
  4. getcwd.c:80: error: for each function it appears in.)

  查看./lib/sh/getcwd.c的源代码,果然没有找到MP_RMDOT宏的定义。在全部源代码中搜索,发现这一定义在externs.h中,在./lib/sh/makepath.c中也有使用,唯独在./lib/sh/getcwd.c中使用了却没有引用其定义。也许这是bash-4.0的一个bug?使用Linux下的gcc编译连接是通过的,但SUA下的gcc版本也许有更严格的名字连接策略,导致无法编译通过。于是我将“#define MP_RMDOT 0x04”的定义手工加入./lib/sh/getcwd.c,再次make,全部通过。实验运行无误!
  需要注意的是,SUA提供的是编译和运行使用了POSIX库的程序的环境,并不提供UNIX二进制文件的运行支持。它编译生成和支持运行的可执行文件仍然是Windows的PE格式,而不是ELF之类。SUA支持的只是仅使用了标准库和POSIX库的程序的源代码级移植,对于使用了Linux等环境特有的系统调用的程序,也不可能不加修改地编译运行。
  有空再研究一下SUA在我们的工程中能有什么实际点的应用。

页面: 上页(较新) 1 2 下页(较旧)