2011年10月8日星期六

压榨 N900 的硬件能力之接近传感器和三轴加速计

总算折腾得能用了。总结一下=.=
N900 可以使用 shortcutd 来定义接近传感器的动作,不过如果使用自定义命令的话长按和短按只能执行同一个命令。 shortcutd 依赖的 proximityd 负责定时监测接近传感器状态并把状态变化消息发送到 dbus 上。用 dbus-script :建立 /etc/dbus-scripts.d/proximity.dbus ,内容是 /home/user/bin/proximity.sh * * proximityd.signal.state changed * 。在 /home/user/bin/proximity.sh 里进行操作,$5 是 closed时在临时文件里留下时间戳, $5 是 open 时用当前时间减去临时文件里的时间,就得到按下的持续时间。这样就可以按照自己的喜好定义不同时长的不同动作了。
我个人比较不喜欢容易引起误操作的触摸屏,看书的时候禁用掉(以 root 身份执行 echo 1 > /sys/devices/platform/omap2_mcspi.1/spi1.0/disable_ts )。不开键盘时可以用 virtkey 模拟键盘。看 pdf 时需要调整页面位置,键盘操作能力有限,于是用 xresponse 模拟触摸屏上的拖动操作。不用键盘也不用触摸屏,我用三轴加速计配合接近传感器实现。还是在上面提到的 /home/user/bin/proximity.sh 里,除了时间戳之外还记下三轴加速计的输出( cat /sys/class/i2c-adapter/i2c-3/3-001d/coord ),由这些数据可以得到从按下到松开手机姿态的改变——为了这个我把脑海角落里高中学的受力分析啊~三角函数啊~立体解析几何啊~都挖出来用了,笑。
设定的操作:不摇晃是向后翻页 (next) ;前后摇晃、即以键盘下边缘为轴旋转是往回翻页;左右摇晃是左右移动页面:在键盘/屏幕平面上顺时针旋转是将页面向右移 26 像素,逆时针是向左移 39 像素(因为拖动操作的门限似乎是 25 像素)。
把三轴加速计的三个输出值看作空间向量,则按下时的向量 (xx,yy,zz) 和松开时的向量 (x,y,z) 之间的夹角就是手机整体的摇晃程度。这个夹角低于门限时认为手机没有摇晃——这个门限和环境有关,在公交车上和在床上取值显然应该不同。目前我只是手动修改,还没想到比较好的自动适应的方法 =。= 三轴加速计输出值可以看作手机在三个互相垂直的方向上受到的力,这三个力的合力在静止的条件下应该就是 1G=1000 mG 。前后摇晃和作用在手机侧面短边的力无关,于是前后摇晃的程度可以简化为平面向量 (yy,zz) 和 (y,z) 的夹角。同理左右摇晃与垂直于屏幕的力无关,可以看作 (xx,yy) 和 (x,y) 的夹角,而摇晃方向具体是顺时针还是逆时针可以由 (x*yy-xx*y) 的正负号判断出来。另一种求平面夹角的思路是求得每个平面向量与数轴的夹角的三角函数值,然后用三角函数的公式——还好这两个思路做出来的结果是一样的。
判断适用哪一个分支的条件组合我还在慢慢探索。假如有人和我一样常常侧躺着看书,就会发觉仅凭三轴加速计 x 一个分量来判断是横屏还是竖屏简直脑残得让人想砸手机(或者是砸那个没有提供禁用自动横屏的程序员)。键盘底边大致平行于水平面的时候还好,侧躺的时候似乎常常得到整体摇晃、前后摇晃、左右摇晃三个角绝对值都不小。观察的经验数据是侧躺的情况下前后摇晃时左右摇晃夹角应该相对比较小。
俺是 bash 新手,把摔的跟头罗列如下。丢人就丢人吧=w=
在 shell 里用 bc -l 计算反三角函数只有 a() 反正切可以用。向量夹角算出来的值是余弦, 转化为正切时要小心分母可能等于 0 ,分别计算正切再和差化积也有这个风险。另外 bc 输出的小数如果绝对值小于 1 ,小数点之前是没有 0 的……也就是说会有 ".473" 或者 "-.211" 这样的结果,取整用于比较之前要处理一下,不然会变成空字符串和数字比大小报错。
时间戳用了 date "+%S%3N" 。首先, N900 自带的 date 是 busybox 里的,不支持 %N ,所以直接说用 /usr/bin/gnu/date "+%S%3N" 才比较保险。 其次,我假定按下持续不超过 60 秒,所以只用了 %S ,结束值比开始值小的话结束值再加 60000 就是了——如果 %S 以 0 开头, shell 会误认为它不是十进制的数。
还有碰到了权限问题,我一直没搞明白 shortcutd 里这个自定义命令是以什么身份运行的,似乎有时候是 root 有时候是 user ,于是好长一段时间里禁用触摸屏的功能总是用不起来。最后索性按照 $(whoami) 判断,如果是 user 的话就执行 sudo sh -c "echo 1 > /sys/devices/platform/omap2_mcspi.1/spi1.0/disable_ts" 。

shortcutd 失效没反应:如果 ps | grep proximityd 没有对应进程,需要重装 proximityd 再 killall shortcutd ;否则的话只需要 killall shortcutd ,五秒之后就恢复正常了。


--

没有评论:

发表评论