Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
[Desarrollo] Airduino v1.0
#1
Ya que nadie se anima a abrir el hilo, y siendo varias las personas interesadas en esta versión, vamos a empezar a tocar algo. Se trata de hacer una base de hardware con la que empezar a programar. Tendremos 2 opciones, o se prueba todo en protoboard, o se hace una shield para el arduino mini (aunque el paso de probar en protoboard es obligatorio).

En su día, miramos de usar el siguiente arduino mini: http://www.ebay.es/itm/181285938269?ssPa...1439.l2649

Realmente no mucho mas puedo decir, porque no he podido pensar mucho sobre esto. Una idea seria hacer la shield y en ella iría conectado el modulo RF. Aparte llevaría los componentes necesarios para suministrar 3v3 y algunos leds de estado. Sacar los pines para conectar lo que sea y poco mas, algo del estilo a la versión de pic.

El siguiente paso, y en colaboración con el otro diseño (pues aunque sea HW algo diferente, la idea es la misma), seria hacer una v2. Placa desde 0 con todos los componentes (fusionaríamos la shield y el arduino en una única placa mas lo que sea necesario).

Es un buen momento para colaborar :one: :one: :one:
Citar
#2
Un ardu con el modulo integrado.. puede ser muy jugoso. Kickstarter... ahí vamos :one:
Citar
#3
jukillo escribió:Un ardu con el modulo integrado.. puede ser muy jugoso. Kickstarter... ahí vamos :one:
El problema de integrar el modulo, es el tamaño del chip del nrf que tiene que ser soldado en un horno. No se si alguien a probado a hacerlo con una pistola de aire caliente y lo ha conseguido, pero en principio eso seria para mandarlo hacer todo en la fabrica, lo cual no saldra ni parecido a los precios que hay ahora (3+1 euro)

Sobre la shield con regulador de 3.3v, en principio no es necesario, ya que hay versiones del arduino tanto en 5v como en 3.3v. Yo creo que seria sencillamente hacer una shield para que encaje el nrf en el arduino de forma solida sin que se mueva. El diseño de la pcb es simplemente unir las lineas del conector con unas que escojamos del arduino, como si fueras cables, ya que realmente no hace falta mas.

El mejor diseño podria ser uno que conecte directamente la bateria al nrf, ajustando el voltaje con algun otro metodo como diodos. De esta forma el arduino no consumiria nada, ya que se eliminaria el regulador/leds que es lo que mas consume en el arduino. Esto es lo que se hace en otros proyectos similares (cortando una pista del regulador de voltaje). Sin mirar los datos de memoria, creo recordar que con el regulador el arduino consume 10mA y sin el 0,1mA lo cual ya es muy prometedor. Y dormido pues ya microA. Con un par de pilas de litio de 3.7 en paralelo (tipo 18650 que son muy baratas), que pueden ser 3500mA, duraria muchos meses sin reemplazarlo, ideal para sensores y cosas asi. Vamos solo habria un consumo real en el momento de transferir datos, y se podria programar algun modo en que solo mande datos cada par de segundos, o un modo dinamico en el que los extremos negocien cuanto dormir y mandar la siguiente informacion.

Igual se puede convinar el corte de este regulador con añadir uno mas apropiado en la shield, con menos consumo.
Citar
#4
Algo mas de info precisa sobre el modulo en arduino (433mhz) con su libreria y algo de faq en los comentarios.

Tienen hasta direccion estos, buena pinta.

http://blog.zakkemble.co.uk/nrf905-avrar...arydriver/
Citar
#5
Tiene buena pinta
Citar
#6
Mi idea.

a) Una shield que conecte con un nrf, conversor a 3,3v incluido.. dos led. 4 pines para conectar un mando de ps2. Mando a distancia universal para robots. Lo tengo montado pero con un led..

Paso el código.

Código:
//first included your library

/*
esquema pines para mi mando

2     DATA      VERDE
4     NARANJA   COMMAND
NC    AZUL      VIBRATION (7VOLTS)
GND   NEGRO     TIERRA
3,3V  AMARILLO  3,3 V
3     ROJO      ATTENTION
5     LILA      CLOCK
NC    BLANCO    CONO


NRF 2401L
13   CSK       MARRON
12   MISO      VERDE
11   MOSI      ROJO-BLANCO
10   CE        NARANJA
9    CSN       GRIS
NC   IRQ       AZUL
3,3            AMARILLO Y BLANCO
GND            MARRON Y MORADO

6   LED      VERDE-BLANCO


*/
#include <PS2X_lib.h>  //for v1.6
#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

PS2X ps2x; // create PS2 Controller Class
int error = 0;
int led = 6;

void setup(){
   Serial.begin(9600);
   pinMode(led, OUTPUT);
   digitalWrite(led, LOW);
    Mirf.spi = &MirfHardwareSpi;
    Mirf.cePin = 10;
    Mirf.csnPin = 9;
    Mirf.init();
    Mirf.setRADDR((byte *)"emiso");
    Mirf.payload = 20;
    Mirf.config();
    error=ps2x.config_gamepad(5,4,3,2,true,true);   //setup pins and settings:  GamePad(clock(lila), command(naranja), attention(rojo), data (verde), Pressures?, Rumble?) check for error
    Serial.println("Beginning ... "); // "Beginning ..." on sender, or "Listening ..." on sever (Receiver)
  }
  
  void loop(){
    
    ps2x.read_gamepad(false, 0);          //read controller and set large motor to spin at 'vibrate' speed
      
    Mirf.setTADDR((byte *)"recep");
    byte Vals[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    
    /*almacenamos valores analogicos en el array
    ButtonReleased
    NewButtonState
    */
    Vals[0]=ps2x.Analog(PSS_LY),DEC;
    Vals[1]=ps2x.Analog(PSS_LX),DEC;
    Vals[2]=ps2x.Analog(PSS_RY),DEC;
    Vals[3]=ps2x.Analog(PSS_RX),DEC;
    Vals[4]=ps2x.Analog(PSAB_PAD_UP),DEC;
    Vals[5]=ps2x.Analog(PSAB_PAD_RIGHT),DEC;
    Vals[6]=ps2x.Analog(PSAB_PAD_LEFT),DEC;
    Vals[7]=ps2x.Analog(PSAB_PAD_DOWN),DEC;
    
    if(ps2x.ButtonPressed(PSB_RED)) //circulo
          Vals[8]=1;
    if(ps2x.ButtonPressed(PSB_PINK)) //cuadrado
          Vals[9]=1;
    if(ps2x.ButtonPressed(PSB_BLUE)) //x
          Vals[10]=1;
    if(ps2x.ButtonPressed(PSB_GREEN)) //triangulo
          Vals[11]=1;
          
    if(ps2x.Button(PSB_L3))
          Vals[12]=1;
    if(ps2x.Button(PSB_R3))
          Vals[13]=1;
    if(ps2x.Button(PSB_L2))
          Vals[14]=1;
    if(ps2x.Button(PSB_R2))
          Vals[15]=1;
    if(ps2x.Button(PSB_L1))
          Vals[16]=1;
    if(ps2x.Button(PSB_R1))
          Vals[17]=1;      
    if(ps2x.Button(PSB_START))                   //will be TRUE as long as button is pressed
         Vals[18]=1;
    if(ps2x.Button(PSB_SELECT))
          Vals[19]=1;
  
    //enviamos los datos  
    
    
    Mirf.send((byte *) &Vals);
    while(Mirf.isSending()){
       //
       //Wait.
      }
    digitalWrite(led, LOW);  
    //imprimimos datos de ejes
    int cont;
    
    /*for (cont=0;cont<20;cont++){
      Serial.print (Vals[cont]);
      Serial.print (" -- ");
    }
    
      Serial.println();
      Serial.println();
    */
    delay(40);
    
    Serial.print (Vals[0]);
    
    if (Vals[0]!=128){
      digitalWrite(led, HIGH);
    }
}

b ) arduino mini nrf con 3,3 v y el resto de pines todos macho y con pines de 5 y gnd al lado para conectar servos. Una placa para robot. También lo tengo funcionando.

Código:
/* buho robot v2.7 04ENE14

03ENE14

-Establecemos limites para el servo BIH graduales. Cuanto mas baja el brazo menos amplitud tiene el servo.
-Aumentamos la velocidad del puerto serial a 57600
-Establecemos limites para el servo BDH graduales. Cuanto mas baja el brazo menos amplitud tiene el servo.
-La marcha adelante y la marcha atras son variables dependiendo de la presion de la cruceta del mando de la play.


antiguo
primer codigo donde solo controlamos motor derechos, izquierdo, brazo izquierdo elevacion y brazo izquiedo giro.


SERVOS Y MOTORES
SERVO [4] MOTOR IZQUIERDO pin 8
SERVO [5] MOTOR DERECHO   pin 7
SERVO [0] BIV             pin 6 0-180
SERVO [1] BIH             pin 5 20(VAR)-130 desde BIV>85 limite inferior se reduce en cinco por cada cinco grados extra del servo.  HASTA 125 QUE TIENE QUE SER 90
SERVO [2] BDV             pin 4 0-178
SERVO [3] DBH             pin 3 0-160(VAR)DEsDE 90 2 grados menos POR CADA grado DE BDV


RECEPTOR NRF24L01
CSN 9 VERDE
CE 10 AZUL
MISO 12 NARANJA BLANCO
MOSI 11 MARRON
CSK 13 AZUL BLANCO

*/
#include <SPI.h>  
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>
#include <Servo.h>     //Libreria de servos





Servo myservo[6]; //DECLARAMOS UN ARRAY DE 3 SERVOS
int   pinservo[6]={6,5,4,3,8,7};//PINES DONDE TENEMOS LOS SERVOS ANCLADOS
int posicionservo[6]={90,90,90,90,73,74}; //Posiciones iniciales de los servos
int valoreje[4]; //valores de los ejes de los servos.
int servomax[4]={185,130,178,165}; //valores maximos de los servos de brazos
int servomin[4]={1,20,1,1}; //valores minimos de los servos de brazos.

int stopServoi=73;
int stopServod=74;
int moviendose=0; //variable para distinguir si el vehiculo ha recibido la orden de moverse.
int esperaservo=500; //mili segundos para la primera configuracion de los servos y que no de un petardazo
int zm=20;           //zona muerta para joystick

void setup(){
    Serial.begin(9600);
    //DECLARACIONES DE MIRF
    Mirf.spi = &MirfHardwareSpi;
    Mirf.csnPin = 9;
    Mirf.cePin = 10;
    Mirf.init();
    Mirf.setRADDR((byte *)"recep");
    Mirf.payload = 20;
    Mirf.config();
    
    //DECLARACIONES DE SERVO
    myservo[0].attach(pinservo[0]);  // Selecionamos el pin 2 como el pin de control para els ervo  
    myservo[0].write(posicionservo[0]);
    delay(esperaservo);
    myservo[1].attach(pinservo[1]);  // Selecionamos el pin 2 como el pin de control para els ervo  
    myservo[1].write(posicionservo[1]);
    delay(esperaservo);
    myservo[2].attach(pinservo[2]);  // Selecionamos el pin 2 como el pin de control para els ervo  
    myservo[2].write(posicionservo[2]);
    delay(esperaservo);
    myservo[3].attach(pinservo[3]);  // Selecionamos el pin 2 como el pin de control para els ervo  
    myservo[3].write(posicionservo[3]);
    delay(esperaservo);
    myservo[4].attach(pinservo[4]);  // Selecionamos el pin 2 como el pin de control para els ervo  
    myservo[4].write(posicionservo[4]);
    delay(esperaservo);
    myservo[5].attach(pinservo[5]);  // Selecionamos el pin 2 como el pin de control para els ervo  
    myservo[5].write(posicionservo[5]);
    delay(esperaservo);
    
      
    
   Serial.println("recibiendo ... "); // "Beginning ..." on sender, or "Listening ..." on sever (Receiver)
  }
  
  ////funcion de mover los servos
  void moverServo(int i, int posicionejes){
    int dif=0;  
    int posservo=0;
    
      posservo=myservo[i].read();
      
      
      dif= map(posicionejes, 0, 255, -8, 9);
            
      if ((posservo>=servomax[i]) || (servomin[i])){ //comprobamos que la posicion del servo no sea mayor que 180 o menos que 0
        posservo=posservo-dif;
      }
      if (posservo>servomax[i]) {
        posservo=servomax[i];
      }
      else if (posservo<servomin[i]){
        posservo=servomin[i];
      }
      
      myservo[i].write(posservo);
    
     /*Serial.print("BIV  ");
     Serial.print(myservo[0].read());
     Serial.print("  BIH ");
     Serial.print(myservo[1].read());
     Serial.print("   BDV  ");
     Serial.print(myservo[2].read());
     Serial.print("   BIH  ");
     Serial.print(myservo[3].read());
         
    
     Serial.println();
   */
  }
//Limite de servo BiH

//evitamos que el brazo izquierdo golpee el robot

void limBIH(){
     if ((myservo[0].read())>90){
      servomin[1]=(myservo[0].read())-90+40;
      if (servomin[1]>90){
          servomin[1]=90;
      }  
        if ((myservo[1].read())<servomin[1]){
         myservo[1].write(servomin[1]);
        }
     }
     else{
       servomin[1]=20;
     }

} //fin funcion limBIH

void limBDH(){
  Serial.println("aqui contador BIH");
     if ((myservo[2].read())<90){
       servomax[3]=160-2*(90-(myservo[2].read()));
        //Serial.println(servomax[3]);
        
        if (servomax[3]<90){
            servomax[3]=90;
          //  Serial.println("minimo de 90");
        }
        
        if ((myservo[3].read())>servomax[3]){
           myservo[3].write(servomax[3]);
           //Serial.println("modificando servo");
        }
        
          
        
     }  
     else{
       servomax[3]=165;
     }
    
} //fin funcion limBDH


//funcion adelante
void adelante(int cruzarriba){
     int vservo5=0;
     int vservo4=0;
     vservo5=map(cruzarriba,0,150, stopServod, 0);
     vservo4=map(cruzarriba,0,150, stopServoi, 180);
     myservo[5].write(vservo5);
     myservo[4].write(vservo4);
     }
//funcion atras
void atras(int cruzabajo){
  int vservo5=0;
  int vservo4=0;
  vservo4=map(cruzabajo,0,150, stopServod, 0);
  vservo5=map(cruzabajo,0,150, stopServoi, 180);
  myservo[5].write(vservo5);
  myservo[4].write(vservo4);
  
}
///funcion pivote izquierda
void izquierda(){
      myservo[5].write(0);
      myservo[4].write(0);
      
      }
///funcion pivote derecha
void derecha(){
      myservo[5].write(180);
      myservo[4].write(180);
      }
    
//funcion alro
void alto(){
      myservo[5].write(stopServod);
      myservo[4].write(stopServoi);
      }


  void loop(){
    //recibimos un array de 20
    moviendose=0;
    byte data[20]={128,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // or int data[32];
     if(Mirf.dataReady()){
          
          Mirf.getData((byte *) &data);
         //Serial.println("recibo");
     }
     //mapeamos array para que los servos vayan correctos
     data[0]=map(data[0], 0, 255, 255, 0);
    
    
    
    
    
    
    
     //iniciamos el bucle de servos
     int cont=0;
     for (cont=0;cont<4;cont++){
       if (((data[cont])>(128+zm))||((data[cont])<(128-zm))){ //si el byte recibido es mayor que la ZM o menos que la ZM
         if ((cont==0)||(cont==1)){
             limBIH();
         }
         else if ((cont==2)||(cont==3)){
             limBDH();
         }
         moverServo(cont,data[cont]);
       }
     }
    
     if (data[4]>1){
     adelante(data[4]);
     moviendose=1;
     }
     else if (data[5]>1){
     derecha();
     moviendose=1;
     }
     else if (data[6]>1){
     izquierda();
     moviendose=1;
     }
     else if (data[7]>1){
     atras(data[7]);
     moviendose=1;
     }
     if (moviendose<1){
     alto();
     moviendose=0;
     }
    
     delay(60);
    
    
    
    
}

aqui un video donde salen el receptor y el emisor ya metidos en robot y mando.

https://www.youtube.com/watch?v=T3AXW7mV_B4
[
Citar
#7
ebludt escribió:aqui un video donde salen el receptor y el emisor ya metidos en robot y mando.

https://www.youtube.com/watch?v=T3AXW7mV_B4

jajajajjajaj vaya abracitos que se descoyunta. Muy bueno Meparto
Citar
#8
Que prisas, pensaba que esperaríais a terminar de programar el modelo con el PIC.


Yo tenia en mente hacer una placa mas elaborada, no solo una mini shield, si no algo que también permita aprender a soldar componentes smd para el que no sepa o no se haya atrevido aun.

La idea seria realizar una placa del tamaño de un Arduino Pro Mini pero a medida, es decir añadiendo los conectores que necesitemos, en la posición que queramos, con el RF, leds o lo que sea.

El elegir "imitar" el pro mini con microcontrolador 328p en vez del pro micro con micro ATMEGA32U4 es sobre todo por precio y tamaño del encapsulado, es bastante mas fácil de soldar el 328p que el otro:

http://arduino.cc/es/uploads/Main/ArduinoProMini.jpg
http://www.robotshop.com/media/files/ima...-large.jpg

En realidad el ATMEGA32U4 también se puede conseguir con el encapsulado del 328p, y viceversa. Pero por ebay salen a unos 6.5€ la unidad... http://www.ebay.es/itm/191120776782
Y en el caso del 328p sale por unos 2.5€ http://www.ebay.es/itm/181165966725 ... viendo precios se ve todo muy caro, y aun habría que sumar el resto de componentes.

Todo eso comprando los componentes sueltos, pero también se podría comprar un pro mini y trasplantarselos a nuestra placa, así saldrá mejor de precio aunque hace falta una pistola de aire o un horno para desoldar los componentes. (Se puede aprovechar todo... o solo el micro, resonador, condensadores y pulsador. Los leds y resistencias se podrían poner de tamaño 0805 para facilitar el montaje)
Por mi parte no tendría ningún problema en pedir yo los pro mini y enviároslos desoldados, se hace en un momento, bueno salvo los leds que se suelen quemar/deshacer.

Arduino Pro Mini a 3.3V 8Mhz

A parte, al usar ese chip perderíamos el usb así que haría falta un conector serial y un programador externo o añadirle un chip ftdi... pero siendo que queremos bajo consumo yo me decantaría por el programador externo.

En cuanto al modulo RF, en vez del típico modulo de 1€ me decantaría por su versión en SMD de 2.5€, así quedaría todo mas compacto y no haría falta hacer 6 perforaciones en placa.

Mini NRF24L01+ SMD

Tanto el Arduino como el rf funcionan a 3.3v, por lo que el resto de sensores que añadiésemos, en placa o vía conector, también tendrían que funcionar con esa tensión.
También se podría hacer en versión 5V aunque haría falta el regulador de tensión a 3.3v para el rf.



No sé. ya diréis que os parece mi idea xD
giltesa.com Mi blog personal sobre informática, electrónica, Arduino, bricolaje, etc.
Citar
#9
Seria lo mas parecido a la version pic, pero en atmega y con bootloader arduino que tb simplifica mucho. Y por la otra cara soldar ese mini nrf pero a ras. Y hacer el diseño para que no sobresalga el nrf por la placa. Buena idea si. Aunque desoldar eso y resoldar esos micros no es nada facil.
Citar
#10
Es para el que quiera hacerlo, ahi queda expuesto.

Recordar que ambas versiones han de tener las mismas funciones o en la medida de lo posible. Lo suyo es llevar en paralelo ambas versiones.

Importante tambien es desarrollar sobre un mismo HW. Ya habra tiempo mas adelante, si fuera necesario, hacer versiones mas especificas.
Citar
#11
Quizas andar soldando y desoldando el micro, a no ser que tengas bastante experiencia y aun asi fatige termicamente al mismo.

Yo desde mi humilde opinion, quizas sea mas asequible integrar el arduino por completo, o buscar la manera de conseguir el 328 barato nose.... Es una pena que atmel no de Samples la verdad

Enviado desde mi Nexus 4 mediante Tapatalk
Citar
#12
No sé, en mi caso ya os digo que me pareció fácil cuando lo hice. Le quite el micro a un nano al que se le había quemado su chip FTDI (y al cual me cargue sus pistas al intentar desoldarlo con soldador), mas adelante cuando tuve la estación de soldadura aproveche para quitarle el micro 328 para ponérselo a un pro mini que venia con un 168, así gano en memoria.

http://giltesa.com/2012/10/14/remplazar-...-pro-mini/

Por otro lado, sin quitarle funcionalidades, se podría adaptar la placa para que entrase en una caja de plástico en vez de tenerlo al aire:

http://www.ebay.com/sch/i.html?_sop=15&_...c&LH_BIN=1
http://www.ebay.es/itm/171185262304 , esta es muy curiosa y permite ser colgada.

--

En cuanto a lo de soldar un Arduino encima directamente... también se podría hacer pero puestos a hacer la placa de cero y pidiéndola a china pues queda mejor todo soldado directamente a la placa.

Edit:
Seria algo asi pero con otro RF, con los conectores a medida, la forma para la caja, etc.

http://nathan.chantrell.net/20130923/tin...ino-clone/
giltesa.com Mi blog personal sobre informática, electrónica, Arduino, bricolaje, etc.
Citar
#13
Pero antes de ir a la placa buena con todo integrado, hay que ir poco a poco por evitar un gran gasto tanto en fabricar placas grandes o en componentes. De ahi mis pasos poco a poco en la version pic. Hay que reducir el gasto y en la version de arduino se va a gastar un pelin mas.
Citar
#14
La versatilidad de Arduino puede suponer un extra muy interesante.
Citar
#15
Desd mi punto de vista se gana versatilidad si se dejan lsmagujerosmpara poder colcsr el mini y el nrf.

Se pueden soldar header hembras el que quiera para cambiarlo si se estropea. Y el que quiera menos tamaño puede soldar el mini a la placa con eses mismos agujeros,
Y por los 3 euros que cuesta el mini no creo que encontremos los atmega.
Citar
#16
Mejor a 5v porque los servos van a 5.
Citar
#17
Siempre se puede usar un elevador de tension.
Citar
#18
Hola, a todos, me quedo por aquí que me parece muy interesante el proyecto Sonrisa

Estoy haciendo pruebas con un arduino mini pro, un nrf24 y un ds18b20. Como medís los consumos del mismo?

Yo lo estoy haciendo con un multimetro, pero solo puedo registrar máximos y mínimos y avg, me gustaría registrarlo en plan datalogger para hacer una gráfica y poder hacer cálculos para de baterías más exactos.

Actualmente estos son los valores que me registra:
sleep mode (SLEEP_MODE_PWR_DOWN) -> 0.82 mA
Máximo (Cuando lee el sensor y envía datos) -> 10.55 mA
Avg -> 0.87 mA (Lo tengo 24 segundos dormido mediante WDT, (3 iteraciones de 8 segundos del WDT))

Saludos! Mola

Edito: Corregidme que creo que estoy equivocado...

Estoy alimentando el cacharro con una pila 18650 de 4000mAh
Segun el consumo medio (0.87 --> 0.9 mA), con la pila cargada completamente, podría durar lo siguiente?
4000 mAh / 0.9 mA = 4444 horas => /24 = 185 días?

Esto esta mal no?
Citar
#19
Tus calculos son correctos. Pero date cuenta que lo enciendes y consumes mas, y eso tambien cuenta, con lo que la vida de la bateria es menor.

Respecto a este proyecto, en los proximos meses se publicaran cosas. Creo que quedara chulo, pero de momento estamos diseñando.
Citar


Temas similares...
Tema Autor Respuestas Vistas Último mensaje
  [Desarrollo] Air v2.0 rev A grafisoft 7 1,104 30-11-2014, 03:15 PM
Último mensaje: grafisoft
  [Desarrollo] Etapa de carga de baterias (Litio/lipo) grafisoft 19 1,324 17-07-2014, 07:10 PM
Último mensaje: grafisoft
  Bienvenidos - Desarrollo grafisoft 62 3,807 13-06-2014, 11:07 AM
Último mensaje: grafisoft
  [Desarrollo] Air v1.0 rev A grafisoft 64 4,319 26-05-2014, 10:22 PM
Último mensaje: grafisoft
  [Desarrollo] Etapa de alimentación - Conversor dc-dc step up grafisoft 7 894 21-05-2014, 03:44 PM
Último mensaje: Triggerr