Saltar al contenido

MIDI amb VL53L0X

Hola Angel;

Avui 5 d’agost m’he decidit a començar a fe la documentació del mòdul d’Arduino “VL53L0X” ja que es un procés d’aprenantaje una mica llarg i no vull perdre el fil del que estic fent i dels inconvenients que hi veig per arribar a la finalitat que em vas proposar.

Hi han dues llibreries que es poden fer servir per utilitzar aquest mòdul, una es d’Adrafruit i l’altre es el propi del mòdul; amb els dos casos el resultat es el mateix, malgrat que el més fiable pel destí final es de Adafruit sense tenir una lògica concloent.

En els dos primers casos que t’exposo, son probes que he fet pel bon funcionament del  mateix.

L’esquema que et presento ens serveix tant pel projecte final com les probes realitzades     

Codi amb la llibreria d’Adafruit

//*****************************************************
// https://www.hwlibre.com/vl53l0x/
// Valor maxim 120 cm depent del ambient
#include "Adafruit_VL53L0X.h"
  
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
#define estat 12
  
void setup() {
  Serial.begin(9600);
//  pinMode(estat, OUTPUT);
  
  // Iniciar sensor
  Serial.println("VL53L0X test");
  if (!lox.begin()) {
    Serial.println(F("Error al iniciar VL53L0X"));
    while(1);
  }
}
  
  
void loop() {
 /*  if (sensor.readRangeContinuousMillimeters() <= 1270){
    Serial.print(sensor.readRangeContinuousMillimeters());
    int j = map(sensor.readRangeContinuousMillimeters(), 1, 1270, 1, 127);
    Serial.print("\t"); Serial.println(j);
    delay(500);
   } */
  VL53L0X_RangingMeasurementData_t measure;
     
  Serial.print("Leyendo sensor... ");
  lox.rangingTest(&measure, false); // si se pasa true como parametro, muestra por puerto serie datos de debug
  
  if (measure.RangeStatus != 4)
  {
    if(measure.RangeMilliMeter <= 1270){
      Serial.print("Distancia (mm): ");
      Serial.print(measure.RangeMilliMeter);
      int j = map(measure.RangeMilliMeter, 1, 1270, 1, 127);
      Serial.print("\t"); Serial.println(j);
      delay(500);
    }
  } 
  else
  {
  //  digitalWrite(estat, HIGH);
    Serial.println("  Fuera de rango ");
  }
     
  delay(100);} 

Codi amb la llibreri especifica del mòdul.

/* Aquest exemple mostra com utilitzar el mode continu per prendre
mesures de rang amb el VL53L0X. Es basa en
vl53l0x_ContinuousRanging_Example.c de l'API VL53L0X.

Les lectures del rang estan en unitats de mm. */
// Valor maxim 8190
#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("No s'ha pogut detectar i inicialitzar el sensor!");
    while (1) {}
  }

   // Inicia el mode contínu d'esquena a esquena (feu lectures com
   // el més ràpid possible). Per utilitzar el mode de temps continu
   // en lloc d'això, proporcioneu un període de mesurament desitjat a
   // ms (p. ex. sensor.startContinuous(100)).
  sensor.startContinuous();
}

void loop()
{
  
  if (sensor.readRangeContinuousMillimeters() <= 1270){
    Serial.print(sensor.readRangeContinuousMillimeters());
    int j = map(sensor.readRangeContinuousMillimeters(), 1, 1270, 1, 127);
    Serial.print("\t"); Serial.println(j);
    delay(500);
  }
//  if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }

//  Serial.println();
}

Segons el que he pogut observar, aquest mòdul te un radi d’acció molt limitat i em don la sensació que per l’aplicació que li volem donar no es el mòdul més adient.

Tot seguit et mostro un diagrama i el seu codi corresponent per si en alguna ocasió li veus alguna utilitat per algun usuari en concret. Em va semblar força útil.

//https://create.arduino.cc/editor/joasalellesma/a4364d91-6f9a-4a9d-9cb8-1775daada948/preview
//Esquema: http://bloctecno.iesgregorimaians.org/2019/06/teclat-midi-maquinari.html
#include <Wire.h>
#include <VL53L0X.h>
/*
 * Interface i2C, amb la llibreria Wire
 * Al Nano i UNO els pins son SDA->A4  i SCL->A5
 */
#define numSensors 13

//#define XSHUT_pin6 not required for address change
//El sensor6 no necessita XSHUT, li canviem adreça el primer
//a quin pin va el primer XSHUT, els demes correlatius tindrem numSensors-1 pins
#define firstXSHUTpin 12

//ADDRESS_DEFAULT 0b0101001 or 41
//#define Sensor1_newAddress 41 not required address change
//el sensor1 el deixem a la seua adreça original
// Les adreces seran 41+numSensors-1 pel sensor que no te XSHUT i despres succesivament decreixents
//No podem deixar cap a 41 (original), excepte el darrer

VL53L0X *sensors[numSensors]; //array d'objectes sensors sensors[0] serà el 1r i sensors[numSensors-1] l'últim

void setup()
{ 
  Serial.begin(115200);
  //instanciem els sensors dins l'array
  for(int thisSensor=0; thisSensor < numSensors; thisSensor++)
  {
    sensors[thisSensor]= new VL53L0X(); //instanciem els numSensors sensors
  }//del for(thisSensor...
  Serial.print(numSensors);
  Serial.println(" sensors instanciats");
  /*WARNING*/
  //Shutdown pins of VL53L0X ACTIVE-LOW-ONLY NO TOLERANT TO 5V will fry them
  //Els pins XSHUT dels lidars no toleren 5V!!! Posant el pin digital al qual va connectat XSHUT com a OUTPUT
  //Activem XSHUT (a LOW) i el lidar eixe es deshabilita
  //Per activar-lo, definim pin com a INPUT, que entra en alta impedancia i per tant la R pull-up interna del 
  //lidar posara XSHUT en HIGH, habilitant-lo
  for(int thisSensor=0; thisSensor < numSensors-1; thisSensor++)
  {
    pinMode(firstXSHUTpin+thisSensor, OUTPUT); 
    digitalWrite(firstXSHUTpin+thisSensor, LOW);
    //
  }//del for(thisSensor...
  delay(500);
  Serial.println("Sensors desactivats excepte solt");
  //Tots els sensors estan deshabilitats excepte el que no te XSHUT
  //Anem a fer que aquest siga el sensors[numSensors-1] i tindrà adreça 41+numSensors-1
  //I el sensors[0] serà el de pin firstXSHUTpin i el deixarem amb l'adreça per defecte 41
  
  Wire.begin(); //Activem bus i2c
  
  //Change address of sensor and power up next one
  for(int thisSensor=numSensors-1; thisSensor>0; thisSensor--)
  {
    sensors[thisSensor]->setAddress(41+thisSensor); //posem nova adreça a sensor actiu
    pinMode(firstXSHUTpin+thisSensor-1, INPUT);  //Activem següent sensor
    delay(10);
    Serial.print("Sensor: ");
    Serial.print(thisSensor);
    Serial.print(" fixat a adress: ");
    Serial.println(41+thisSensor);
  }
  /* Així ja tenim
     sensors[numSensors-1] adreça 41+numSensors-1 no te XSHUT connectat
     sensors[numSensors-2] adreça 41+numSensors-2 XSHUT a darrer pin
     ...
     sensors[1]            adreça 42, XSHUT al segon pin
     sensors[0]            adreça 41 (no la canviem!), XSHUT al pin firstXSHUTpin
  */
  
  //inicialitzem, posem timeout i arranquem en mode continu
  for(int thisSensor=0; thisSensor < numSensors; thisSensor++)
  {
    sensors[thisSensor]->init();
    sensors[thisSensor]->setTimeout(500);
    sensors[thisSensor]->startContinuous();
    Serial.print("Sensor: ");
    Serial.print(thisSensor);
    Serial.println(" inicialitzat i arrancat");
  }
  // Start continuous back-to-back mode (take readings as
  // fast as possible).  To use continuous timed mode
  // instead, provide a desired inter-measurement period in
  // ms (e.g. sensor.startContinuous(100)).
} //del setup()

void loop()
{
  for(int thisSensor=0; thisSensor < numSensors; thisSensor++)
  {
    Serial.print("Sensor ");
    Serial.print(thisSensor);
    Serial.print(": ");
    Serial.print(sensors[thisSensor]->readRangeContinuousMillimeters());
    Serial.print("\t");
  }
  Serial.println();
  delay(500);
}

En el projecte final que et deixo no he fet servir cap component, només he fet servir el mòdul de proximitat per tal de controlar el volum,. La resta, el que he fet es un bucle FOR per tal que recorri totes les notes de l’octava del mig.

Et deixo el link de l’aplicació que he fet servir “Synthesia”, també es pot fer servir al software de “Abelton”, per cal tenir en conte que no s’ha de mapejar el control del volum.

En la última gràfica que et deixo, es la representació de totes les notes musicals amb les seves respectives octaves.

Si el projecte us es útil, ja que jo no veig clar la utilització d’aquest sensor en aquets projecte, se li poden donar mes funcionalitat. Espero que sigui del vostre agrat.

// Probado en arduino Leonardo.
// URL d'on hi tet la bsa per for-ho:
// https://www.youtube.com/watch?v=pIFoOQJEFZ0&t=8s&ab_channel=DHCast
// URL de les espacifiucacions del mòdul "VL53LOX"
// https://www.hwlibre.com/vl53l0x/

#include <Adafruit_VL53L0X.h>
#include <MIDIUSB.h>

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

int volum = 64; //Es el volum que estableixo d'entrada
int notes[] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}; //Definició de l'octava del mig
  
void setup() {
  Serial.begin(9600);
  
  // Iniciar sensor
  Serial.println("VL53L0X test");
  if (!lox.begin()) {             // En cas que la placa no detecti el sensor de proximitat entre en un bucle
    Serial.println(F("Error al iniciar VL53L0X"));
    while(1);
  }
}

void loop(){
 
  for (int i = 0; i <= 12; i = i + 1) {   // Reproduim l'escala msical definida en l'array
     contolVolum();                       // Control del volum
     noteOn(0,notes[i],volum);
     MidiUSB.flush();
     delay(500);
  }

}


void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOn);
}

void noteOff(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
  MidiUSB.sendMIDI(noteOff);
}

void contolVolum(){
  VL53L0X_RangingMeasurementData_t measure;
     
  //Serial.print("Leyendo sensor... ");
  lox.rangingTest(&measure, false); // si se pasa true como parametro, muestra por puerto serie datos de debug
  
  if (measure.RangeStatus != 4)
  {
    if(measure.RangeMilliMeter <= 1270){
      Serial.print("Distancia (mm): ");
      Serial.print(measure.RangeMilliMeter);
      volum = map(measure.RangeMilliMeter, 1, 1270, 1, 127);
      Serial.print("\t"); Serial.println(volum);
      delay(50);
    }
  } 
  else{
    Serial.println("Fora del radi d'acció");
  }
}
Taula de les diferentes octaves

En aquest últim projecte que et deixo a continuació he fet el mateix però amb la llibreria MIDI de l’Ordino.

Tot hi havent frasejat la tarja amb el programa “Flit” per tal de convertir el dispositiu com a n dispositiu Midi, no he sabut com executar l’aplicació per tal de veure el seu correcte funcionament.

Si tu em pots explicar com ho he de fer per veure els resultat, m’aniria be per futurs projectes.

Aquets dos últims projectes, l’únic que fan es l’escala musical del mig per veure el correcte funcionament del sensor de proximitat.

Espero haver-te ajudat. Per qualsevol cosa pots contar amb mi.

// https://www.automatismos-mdq.com.ar/blog/2021/01/usando-el-protocolo-midi-con-arduino.html
#include <MIDI.h>
#include <Adafruit_VL53L0X.h>

MIDI_CREATE_DEFAULT_INSTANCE();

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

int volum = 64; //Es el volum que estableixo d'entrada
int notes[] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59}; //Definició de l'octava del mig


void setup() {
  Serial.begin(57600);
  
  // Iniciar sensor
  Serial.println("VL53L0X test");
  if (!lox.begin()) {             // En cas que la placa no detecti el sensor de proximitat entre en un bucle
    Serial.println(F("Error al iniciar VL53L0X"));
    while(1);
  }
}


void loop() {
  for (int i = 0; i <= 12; i = i + 1) {   // Reproduim l'escala msical definida en l'array
     contolVolum();                       // Control del volum
     MIDI.sendNoteOn(notes[i],volum,1);   //Nota, intensitat o volum, canal
     delay(500);
     MIDI.sendNoteOff(notes[i],volum,1);
     delay(500);
  }
}

void contolVolum(){
  VL53L0X_RangingMeasurementData_t measure;
     
  //Serial.print("Leyendo sensor... ");
  lox.rangingTest(&measure, false); // si se pasa true como parametro, muestra por puerto serie datos de debug
  
  if (measure.RangeStatus != 4)
  {
    if(measure.RangeMilliMeter <= 1270){
      Serial.print("Distancia (mm): ");
      Serial.print(measure.RangeMilliMeter);
      volum = map(measure.RangeMilliMeter, 1, 1270, 1, 127);
      Serial.print("\t"); Serial.println(volum);
      delay(50);
    }
  } 
  else{
    Serial.println("Fora del radi d'acció");
  }
}

 16 total visitantes