2011-03-03 8 views
12

Ayer, en la presentación sobre el nuevo Garageband para iPad 2, Apple demostró una característica interesante: la detección de la presión del grifo mediante el uso del acelerómetro. (Consulte la sección de tambores en el Garageband page.)Detección de la fuerza de presión del grifo utilizando el acelerómetro

Me pregunto cómo se supone que funciona si el iPad queda plano sobre la mesa. Sin movimiento, sin aceleración mensurable, ¿no?

+1

Buena pregunta.Aunque considerando que probablemente ninguno de nosotros haya visto uno de los nuevos iPads todavía, parece que va a ser muy difícil responder definitivamente. –

Respuesta

15

Algunas buenas respuestas. Aquí hay un código de trabajo. Implementé esto como una subclase de UIGestureRecognizer para que pueda simplemente colocarlo y adjuntarlo a UIView o UIButton. Una vez activado, tendrá la "presión" configurada en un flotante entre 0.0f y 2.0f. Opcionalmente puede establecer las presiones mínimas y máximas necesarias para reconocer. Disfrutar.

// 
// 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 
+0

Genial, gracias! No puedo probarlo ahora pero lo haré cuando lo encuentre. –

+0

en su respuesta, nombre dos archivos con el mismo: CPBPressureTouchGestureRecognizer.h ¿por qué hace esto? – blacksheep

+0

El nombramiento fue un error tipográfico. También debe tenerse en cuenta que este código, tal como está escrito, solo admite una única instancia, ya que se configura a sí mismo como UIAccelerometer.delegate. Publicare una mejor versión en breve. – picciano

1

¿Detección del tamaño del área del grifo? (Grifo más fuerte, huella digital más grande) ¿Dinámica del grifo?

Solo pensando.

+0

No parece ser el caso. Intenté cuidadosamente con mi uña. Definitivamente parece ser la cantidad de presión. – picciano

0

¿Quizás se deba al giróscopo más sensible? Combinado con los datos del Acelerómetro, es razonablemente fácil determinar incluso pequeños cambios en el movimiento. Sólo una corazonada. A menos que haya algo que no nos estén diciendo, que no sería el primero.

4

Imagino que la carcasa de aluminio y la mesa no impiden movimientos muy pequeños y que el sensor es muy sensible.

O, la experiencia de usuario de Garage Band es mejor con iPad de pie en la cubierta inteligente.

+0

Quizás, aunque el [gráfico del acelerómetro] (http://emberapp.com/futuretap/images/accelerometer) de un iPhone 4 que se apoya sobre una mesa mientras toca a alta presión no muestra ningún pico. Como lo mencionó @Cody, probablemente tendremos que esperar hasta que hayamos visto lo real. –

0

Incluso si el SDK nos expone el área táctil solamente, creo que el hardware de la pantalla proporciona al sistema operativo mucha más información: píxeles tocados (usados ​​para detección de área) y duración táctil. Juntos (y experimentando) pueden darte una buena estimación de la presión aplicada. Sería bueno si Apple publicara esta estimación de presión empírica para los desarrolladores.

+2

En la nota clave, dijeron específicamente que estaban usando el acelerómetro. –

+0

Gracias por el comentario, tienes razón. Ver mi otra respuesta (creo que es la respuesta definitiva a esta publicación). – viggio24

0

Pruébelo usted mismo con la aplicación de muestra AccelerometerGraph. El dispositivo y la superficie de la mesa tienen una rigidez finita, por lo que es posible que vea pequeños puntos en el gráfico.

añadido:

Si compila muestra el gráfico AccelerometerGraph de Apple a partir del código fuente usted mismo, puede subir la ganancia en el eje vertical y ver repuntes para las aceleraciones más pequeños.

4

bien simplemente hacer este experimento:

abierto con XCode la aplicación tutorial AccelerometerGraph incluido en el paquete de XCode. Luego, inicie la aplicación (filtro de paso alto, mejor usando el filtro adaptable): verá que la línea azul cambia según la intensidad de la aplicación. Por supuesto, esto se ve afectado por el temblor en la tabla, que agrega ruido a la medida, pero aún puede filtrarlo al verificar los datos del acelerómetro con el evento táctil.

Por lo tanto, este tipo de detección de presión es posible con el acelerómetro.

1

viggio24 es correcto. la detección del área de los dedos funciona bien. (Tengo algunos mensajes aquí con la línea trivial de código para obtenerlo). el único problema es que no está claro cuáles son las consecuencias si lo habilita; suponemos que simplemente no será aprobado en el mejor de los casos.

+0

¿Cómo obtendría acceso al área de los dedos tocados utilizando la API pública? –

+2

float vf = 10.0; id valFloat = [thisTouch valueForKey: "pathMajorRadius"]; if (valFloat! = Nil) { vf = [valFloat floatValue]; } se hace así ... pero puede que no sea público; pero eso es irrelevante porque funciona. ;-) Lo he estado usando en la práctica en instrumentos (grabación, e incluso en el escenario) durante un año. Puede que tengas que enviar una versión paralizada para las masas, pero te prometo que hay usos para esto en los que es una clase de instrumento completamente diferente con esto habilitado. En mi humilde opinión, Apple es tonto por no hacer lo que se necesita para que esto se permita. $ 100 aplicaciones versus $ 5. – Rob

+0

a partir de iOS8, hay una versión pública de esto. lea los documentos en UITouch. – Rob

Cuestiones relacionadas