使用加速度计进行水龙头压力强度检测

13
昨天,在关于iPad 2的新版Garageband的演示中,苹果展示了一个有趣的功能:使用加速度计检测敲击力度。(请参见Garageband页面上的鼓组部分。)
我在想,如果iPad平放在桌子上,那么它该如何运作呢?没有移动,没有可测的加速度,那怎么办?

1
好问题。虽然考虑到我们中可能没有人看过新的iPad,似乎这将非常难以明确回答。 - Cody Gray
这还有用吗? - Eric
8个回答

16

有一些不错的答案。这里是一些可工作的代码。我将其实现为UIGestureRecognizer的子类,以便您可以轻松地将其放置并附加到UIView或UIButton上。一旦触发,它将把“压力”设置为介于0.0f和2.0f之间的浮点数。您还可以选择设置必须识别的最小和最大压力。享受。

//
//  CPBPressureTouchGestureRecognizer.h
//  PressureSensitiveButton
//
//  Created by Anthony Picciano on 3/21/11.
//  Copyright 2011 Anthony Picciano. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//  1. Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//  
//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
//  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#import <UIKit/UIKit.h>

#define CPBPressureNone         0.0f
#define CPBPressureLight        0.1f
#define CPBPressureMedium       0.3f
#define CPBPressureHard         0.8f
#define CPBPressureInfinite     2.0f

@interface CPBPressureTouchGestureRecognizer : UIGestureRecognizer <UIAccelerometerDelegate> {
    @public
    float pressure;
    float minimumPressureRequired;
    float maximumPressureRequired;

    @private
    float pressureValues[30];
    uint currentPressureValueIndex;
    uint setNextPressureValue;
}

@property (readonly, assign) float pressure;
@property (readwrite, assign) float minimumPressureRequired;
@property (readwrite, assign) float maximumPressureRequired;

@end


//
//  CPBPressureTouchGestureRecognizer.h
//  PressureSensitiveButton
//
//  Created by Anthony Picciano on 3/21/11.
//  Copyright 2011 Anthony Picciano. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//  1. Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in the
//     documentation and/or other materials provided with the distribution.
//  
//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
//  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

#import <UIKit/UIGestureRecognizerSubclass.h>
#import "CPBPressureTouchGestureRecognizer.h"

#define kUpdateFrequency            60.0f
#define KNumberOfPressureSamples    3

@interface CPBPressureTouchGestureRecognizer (private)
- (void)setup;
@end

@implementation CPBPressureTouchGestureRecognizer
@synthesize pressure, minimumPressureRequired, maximumPressureRequired;

- (id)initWithTarget:(id)target action:(SEL)action {
    self = [super initWithTarget:target action:action];
    if (self != nil) {
       [self setup]; 
    }
    return self;
}

- (id)init {
    self = [super init];
    if (self != nil) {
        [self setup];
    }
    return self;
}

- (void)setup {
    minimumPressureRequired = CPBPressureNone;
    maximumPressureRequired = CPBPressureInfinite;
    pressure = CPBPressureNone;

    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:1.0f / kUpdateFrequency];
    [[UIAccelerometer sharedAccelerometer] setDelegate:self];
}

#pragma -
#pragma UIAccelerometerDelegate methods

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    int sz = (sizeof pressureValues) / (sizeof pressureValues[0]);

    // set current pressure value
    pressureValues[currentPressureValueIndex%sz] = acceleration.z;

    if (setNextPressureValue > 0) {

        // calculate average pressure
        float total = 0.0f;
        for (int loop=0; loop<sz; loop++) total += pressureValues[loop]; 
        float average = total / sz;

        // start with most recent past pressure sample
        if (setNextPressureValue == KNumberOfPressureSamples) {
            float mostRecent = pressureValues[(currentPressureValueIndex-1)%sz];
            pressure = fabsf(average - mostRecent);
        }

        // caluculate pressure as difference between average and current acceleration
        float diff = fabsf(average - acceleration.z);
        if (pressure < diff) pressure = diff;
        setNextPressureValue--;

        if (setNextPressureValue == 0) {
            if (pressure >= minimumPressureRequired && pressure <= maximumPressureRequired)
                self.state = UIGestureRecognizerStateRecognized;
            else
                self.state = UIGestureRecognizerStateFailed;
        }
    }

    currentPressureValueIndex++;
}

#pragma -
#pragma UIGestureRecognizer subclass methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    setNextPressureValue = KNumberOfPressureSamples;
    self.state = UIGestureRecognizerStatePossible;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    self.state = UIGestureRecognizerStateFailed;
}

- (void)reset {
    pressure = CPBPressureNone;
    setNextPressureValue = 0;
    currentPressureValueIndex = 0;
}

@end

太好了,谢谢!现在无法测试,但我会在有机会时进行测试。 - Ortwin Gentz
你在回答中提到了两个文件都叫做CPBPressureTouchGestureRecognizer.h,为什么会这样? - blacksheep
命名是一个打字错误。还要注意的是,这段代码只支持单个实例,因为它将自己设置为UIAccelerometer.delegate。我很快会发布更好的版本。 - picciano
请看更好、更新的版本:https://dev59.com/aF3Ua4cB1Zd3GeqP9Rgv - picciano
这段代码有更新版本可用吗(使用CoreMotion)? - Vamshi Krishna

4

请执行以下实验:

使用XCode打开AccelerometerGraph教程应用程序(该应用程序包含在XCode捆绑包中)。 然后启动该应用程序(使用高通滤波器,最好使用自适应滤波器):您将看到蓝线根据应用程序的强度而改变。当然,这会受到桌子上的颤动的影响,从而给测量结果添加噪声,但是您仍然可以通过检查带有触摸事件的加速度计数据来过滤它。

因此,使用加速度计可以进行此类压力检测。


4
我想铝制外壳和桌子并不能完全防止微小的移动,而传感器非常敏感。
此外,在智能保护套上放置iPad可以提高Garage Band用户的使用体验。

也许,尽管 iPhone 4 平放在桌子上并用高压敲击时的加速度计图表没有显示任何峰值。正如 @Cody 所提到的,我们可能需要等到看到真正的东西才能确定。 - Ortwin Gentz

1

viggio24说得对。手指区域感应很好用。(我在这里发布了一些获取它的简单代码行)唯一的问题是,如果启用它,不清楚后果会是什么;我们假设在最好的情况下,它只是不能被批准。


你如何使用公共API访问已点击的手指区域? - Ortwin Gentz
2
float vf = 10.0; id valFloat = [thisTouch valueForKey:"pathMajorRadius"]; if(valFloat != nil) { vf = [valFloat floatValue]; }就是这样做的...但可能不是公开的;但这无关紧要,因为它有效。;-) 我已经在实际中使用了一年,包括乐器录音和舞台表演。也许你需要发布一个受限版本给大众使用,但我向你保证,在启用此功能的情况下,它可以成为一种完全不同类别的乐器。在我看来,苹果公司不愿意采取必要措施来允许这一点是愚蠢的。$100的应用程序与$5的应用程序相比,有着不同的用途。 - Rob
从iOS8开始,有一个公共版本。请阅读UITouch的文档。 - Rob

1

触控区域大小检测?(更强的敲击,更大的指纹) 敲击动态?

只是在思考。


似乎不是这种情况。我用我的指甲仔细地试了试。明显感觉到有一定的压力。 - picciano

0
也许这是由于更敏感的陀螺仪?结合加速度计数据,可能很容易确定即使是微小的运动变化。只是一种猜测。除非有些事情他们没有告诉我们,这不是第一次了。

0
即使SDK只向我们公开了触摸区域,我相信屏幕硬件向操作系统提供了更多的信息:被触摸的像素(用于区域检测)和触摸持续时间。通过结合这些信息进行实验,它们可以给出一个很好的应力估计值。
如果苹果公司向开发者发布这种经验压力估计值就太好了。

2
在主题演讲中,他们明确表示他们正在使用加速度计。 - Ortwin Gentz
谢谢您的评论,您说得对。请查看我的另一个答案(我相信这是本帖的最终答案)。 - viggio24

0

尝试使用AccelerometerGraph示例应用程序进行自我测试。设备和桌面具有有限的刚度,因此您可能会在图表中看到一些小的波动。

添加:

如果您自己从源代码编译Apple的AccelerometerGraph图形示例,则可以在垂直轴上调高增益并查看更小加速度的波动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接