【问题标题】:Tap pressure strength detection using accelerometer使用加速度计的敲击压力强度检测
【发布时间】:2011-03-03 10:24:49
【问题描述】:

昨天,在关于 iPad 2 新 Garageband 的演示中,Apple 演示了一个有趣的功能:使用加速度计检测敲击压力。 (请参阅Garageband page 上的鼓部分。)

我想知道如果 iPad 平放在桌子上,它应该如何工作。没有运动,没有可测量的加速度,不是吗?

【问题讨论】:

  • 好问题。尽管考虑到我们当中可能还没有任何人见过新 iPad,但似乎很难明确回答。
  • 这仍然相关吗?

标签: ios iphone ipad uikit accelerometer


【解决方案1】:

一些很好的答案。这是一些工作代码。我将它实现为 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

【讨论】:

  • 太好了,谢谢!现在无法测试它,但我会测试它。
  • 在您的回答中,您使用相同的名称命名了两个文件:CPBPressureTouchGestureRecognizer.h 为什么要这样做?
  • 命名有误。另外值得注意的是,这段代码只支持单个实例,因为它将自己设置为 UIAccelerometer.delegate。我很快就会发布更好的版本。
  • 在这里查看更好、更新的版本:stackoverflow.com/questions/8079580/…
  • 此代码是否有可用的更新版本(使用 CoreMotion)?
【解决方案2】:

我想铝制外壳和桌子不会阻止非常小的运动,而且传感器非常敏感。

或者,如果 iPad 放在 Smart Cover 上,Garage Band 用户体验会更好。

【讨论】:

  • 也许吧,尽管 iPhone 4 平放在桌子上并用高压敲击时的accelerometer graph 没有显示任何尖峰。正如@Cody 提到的,我们可能不得不等到我们看到真实的东西。
【解决方案3】:

简单地做这个实验:

使用 XCode 打开 XCode 包中包含的 AccelerometerGraph 教程应用程序。 然后启动应用程序(高通滤波器,最好使用自适应过滤):您会看到蓝线根据应用程序的强度而变化。当然这会受到表格抖动的影响,这会给测量增加噪音,但您仍然可以通过触摸事件检查加速度计数据来过滤它。

所以这种压力检测使用加速度计是可能的。

【讨论】:

    【解决方案4】:

    点击区域大小检测? (用力敲击,指纹更大) 点击动态?

    只是想。

    【讨论】:

    • 似乎并非如此。我用指甲仔细地试了试。绝对似乎是压力的大小。
    【解决方案5】:

    viggio24 是对的。手指区域感应工作正常。 (我在这里有一些帖子用简单的代码行来获取它)。唯一的问题是,如果您启用它,不清楚后果是什么;我们假设它根本不会在最好的情况下获得批准。

    【讨论】:

    • 如何使用公共 API 访问被点击的手指区域?
    • 浮动 vf = 10.0; id valFloat = [thisTouch valueForKey:"pathMajorRadius"]; if(valFloat != nil) { vf = [valFloat floatValue];它是这样完成的......但它可能不是公开的;但这无关紧要,因为它有效。 ;-) 我已经在乐器(录音,甚至舞台上)中使用它一年了。你可能不得不为大众提供一个残缺的版本,但我向你保证,它有一些用途,它是一种完全不同的乐器,启用了这个功能。恕我直言,Apple 是愚蠢的,因为它没有做任何事情来获得允许。 100 美元的应用程序与 5 美元的应用程序。
    • 从 iOS8 开始,有一个公开的版本。阅读 UITouch 上的文档。
    【解决方案6】:

    也许是因为陀螺仪更灵敏?结合加速度计数据,即使是微小的运动变化也可能相当容易确定。只是一种预感。除非有什么他们没有告诉我们的,否则这不会是第一次。

    【讨论】:

      【解决方案7】:

      即使 SDK 只向我们公开触摸区域,我相信屏幕硬件也向操作系统提供了更多信息:触摸像素(用于区域检测)和触摸持续时间。它们一起(和试验)可以为您提供对施加压力的良好估计。 如果 Apple 向开发人员发布这种经验压力估计,那就太好了。

      【讨论】:

      • 在主题演讲中,他们明确表示他们正在使用加速度计。
      • 感谢您的评论,您是对的。查看我的另一个答案(我相信这是这篇文章的最终答案)。
      【解决方案8】:

      使用 AccelerometerGraph 示例应用自行尝试。设备和桌面的刚度有限,因此您可能会在图中看到一些小光点。

      添加:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-01
        相关资源
        最近更新 更多