Enginursday: Comutação de sensores com um driver de LED endereçável WS2811 - Notícias

Enginursday: Comutação de sensores com um driver de LED endereçável WS2811 – Notícias

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


Enfrentar a difícil tarefa de conectar 192 do mesmo sensor I2C inspirou uma solução criativa.





Favorito



Favorito


0 0

Às vezes nos inscrevemos para fazer coisas malucas – como saltar de pára-quedas com seu melhor amigo ou correr uma maratona em chinelos. Nesse caso, acabei traçando um plano para usar 192 do mesmo sensor I2C em uma instalação interativa. À medida que o tamanho e a complexidade do objetivo diminuíam, fiquei cada vez mais curioso se havia uma maneira simples de conectar todos esses sensores. O resultado é elegante na teoria, barulhento na realidade e provavelmente não funcionará em escala. No entanto, é realmente divertido falar sobre isso, fique por perto para ouvir sobre o uso de drivers de LED endereçáveis ​​como opções de software!

Uma equipe colaborativa

A tarefa: criar uma instalação interativa que permita que crianças pequenas brinquem com som e cor de forma colaborativa. Quando o Museu de Boulder me pediu e Joe Ryan criou isso, começamos a pensar grande! A idéia fantástica de Joe era criar uma equipe musical maior do que a vida na qual as crianças pudessem colocar notas para criar sua própria música. A cor das notas determinaria que tipo de instrumento foi usado. Depois de escolher um tamanho (quatro compassos, quatro posições por compasso e 12 notas por posição), precisávamos encontrar uma maneira de fazê-lo realmente funcionar.

Nós de cores

A detecção de cores foi facilitada por ICs, como o ISL29125. A idéia geral era usar um desses em todas as posições das notas, juntamente com um LED endereçável que pudesse ser usado para iluminar as notas para uma leitura e servir como um guia visual para começar. Um sistema central faria leituras para determinar quais notas deveriam ser tocadas e por quais instrumentos. O desafio foi conectar 192 dispositivos I2C que usam o mesmo endereço.

Existem várias maneiras de realizar essa tarefa – talvez usando uma árvore de multiplexadores I2C, usando vários grupos de sensores independentes, cada um com seu próprio microcontrolador, e até métodos extravagantes usando a comunicação sem fio. Eu procurei uma solução que minimizasse o custo e a complexidade da instalação. O que encontrei foi o IC do driver de LED endereçável WS2811.

Design de switch baseado em WS2811

Saber que os dados do LED precisariam ser enviados para todos os nós me deu uma idéia – e se a energia do sensor de cores pudesse ser controlada da mesma maneira? Talvez isso permita que todos os sensores compartilhem um barramento I2C, desde que apenas um seja alimentado por vez. Em retrospecto, é difícil lembrar quais termos de pesquisa me levaram exatamente ao que eu precisava, mas eventualmente encontrei a folha de dados do WS2811. Um companheiro do popular led endereçável WS2812B, o WS2811 encapsula o mesmo driver, mas quebra os pinos de saída R, G e B para que você possa conectar seus próprios LEDs.

A folha de dados indicava que as saídas eram drenos de corrente constante de até 18,5 mA. Não é o ideal – uma saída de tensão controlável teria sido mais simples de usar, mas felizmente sabemos como converter corrente em tensão e vice-versa.

V = R
I = 18,5 mA
V = 3,3 V (usando a tensão de alimentação ISL29125)
R = V / I = (3,3 / 0,0185) = 178,37 Ω

Um resistor de 178,37 ohm com corrente de 18,5 mA passando por ele cairá 3,3 V. Em outras palavras, um driver de corrente constante configurado para extrair 18,5 mA de 3,3 V a um resistor de 178,37 ohm precisaria definir sua saída em 0V!

Leia Também  Cypress Semi anuncia controladores USB-C para reduzir a pegada de projeto de dispositivos habilitados para USB

Agora não é tão simples, infelizmente. Seria se o driver de LED fosse um driver de corrente constante “analógico” verdadeiro, mas os drivers de LED normalmente usem PWM (Pulse Width Modulation) para aproximar a corrente constante. O ciclo de serviço do sinal PWM é o que percebemos como o brilho do LED. Ao tentar usar um driver de LED como um interruptor, você encontra um problema – o seu interruptor muda com bastante frequência, mesmo quando você o define em apenas um valor!

Diagrama do ciclo cutâneo PWM

diagrama de ciclo de serviço pwm

Imagem: Site do desenvolvedor Android

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

Você pode esperar que pedir ao LED um ciclo de trabalho de 0% ou 100% funcione bem o suficiente, mas não podemos garantir como o driver opera. No caso do WS2811, descobri que um valor de canal 0 resulta em um verdadeiro ciclo de trabalho de 100% (isso faz sentido para um driver de LED de ânodo comum), mas o valor máximo (255) se aproxima apenas de um ciclo de trabalho de 6%.

A capacidade de atingir um verdadeiro ciclo de trabalho de 100% é boa para alimentar o sensor, pois significa ruído mínimo. O fato de que a tensão de alimentação ocasionalmente aumenta, no entanto, é preocupante, pois isso pode causar a ativação de qualquer um dos sensores e interferir na comunicação no barramento I2C. Para combater isso, usei um filtro RC passa-baixo que incorpora o resistor limitador de corrente.

O WS2811 usa uma frequência PWM de 2 kHz, portanto, um pulso de 6% teria uma largura de (6/100) • (1/2000) = 30 μs. Um pulso de onda quadrada de 30 μs contém muitos componentes de frequência, sendo o mais lento (1/30 μs) = 33,3 kHz. Para bloquear essa frequência, seria necessário escolher uma frequência de canto abaixo desse valor. Usando um circuito simulado em falstad.com/circuit, eu brinquei com vários valores de capacitor para obter um bom equilíbrio entre o bloqueio de alta frequência (valores mais altos do capacitor) e o tempo necessário para ligar um sensor (valores baixos do capacitor)

simulador de circuito falstad para filtro RC na saída do driver de LED

simulação de falstad.com/circuit do comutador WS2811

fc = 1 / (2 • π • R • C)
R = 220 Ω (escolha um valor de resistor comum maior que 170,37 Ω)
C = 1 μF
fc = 1 / (2 • π • 220 • 1 • 10-6) = 723 Hz

Utilizando os parâmetros de projeto acima, expus um esquema de protótipo e uma placa no Eagle.

esquema esquemático em Eagle PCB

Teste

Em um esforço para me mover rapidamente, pedi PCBs e os ICs do driver WS2811 ao mesmo tempo. De fato, meu projeto original usava um circuito um pouco mais complicado que eu era capaz de simplificar durante os testes. Nós discutimos o circuito simplificado, mas as placas contêm alguns componentes extras e várias correções de fio branco. Essa é uma lição de por que você deve sempre fazer uma verificação de pacote na escala 1: 1 para todas as peças novas que você pretende usar! Abaixo está uma imagem do protótipo testado:

protótipo v01 com correções de fio branco e circuito simplificado

Para testar o quadro, escrevi um esboço de teste rápido. Ele usa a biblioteca FastLED para controlar a linha de dados do LED (para o WS2811 e o LED do iluminador WS2812B) e a biblioteca SparkFun ISL29125 Arduino para ler a partir do sensor RGB.

/******************************************************************************
Color_Node_Test.ino

Test sketch for for turning on/off an ISL29125 RGB sensor using a WS2811 LED 
driver IC. 

Owen Lyke 
25 Mar 2020

Requires:
SparkFun_ISL29125_Arduino_Library
FastLED library by Daniel Garcia
ESP32 based microcontroller such as the SparkFun ESP32 Thing Plus (https://www.sparkfun.com/products/15663)

Setup:
- Build your own color node based on the schematics shown at: https://www.sparkfun.com/news/3266
- Connect the I2C pins SCL and SDA to the Wire port of your ESP32 based board
- Connect the LED data line to pin 18 of the ESP32 on your board
- Connect GND and 5V lines

This code is beerware.
Distributed as-is; no warranty is given. 
******************************************************************************/

/********************/
/* USER SETUP BEGIN */

#define DISPLAY_TITLES 1      // 1 to print field names to serial
#define DISPLAY_RGB 0           // 1 to print r g b values to serial
#define DISPLAY_HUE 1           // 1 to print computed h value to serial
#define DISPLAY_COLOR 1         // 1 to print nearest color to serial

// Define a type to hold detectable colors
typedef struct _color_t {
  float hue;
  const char* name;
}color_t;

// Here's the list of colors that the system can name on its own (you may add your own based on hue angle [0.0, 360] )
color_t colors[] = {
  {0.0, "Red"},
  {60.0, "Yellow"},
  {120.0, "Green"},
  {180.0, "Cyan"},
  {240.0, "Blue"},
  {300.0, "Magenta"},
};

/* USER SETUP END */
/******************/

// Includes
#include 
#include 
#include           // Click here to get the library: http://librarymanager/All#FastLED_Daniel_Gracia
#include "SparkFunISL29125.h" // Click here to get the library: http://librarymanager/All#SparkFun_ISl29125

// RGB sensor control
SFE_ISL29125 RGB_sensor;
unsigned int red = 0;
unsigned int green = 0;
unsigned int blue = 0;

// WS2811 / WS2812B control
#define DATA_PIN 18
#define NUM_LEDS 2    // Each color node has two 'leds' - one WS2811 to control the sensor power and one WS2812B for illumintation
CRGB leds[NUM_LEDS];

void setup() {
  Serial.begin(115200);                                     // Start Serial 

  FastLED.addLeds(leds, NUM_LEDS);

  sensorPower(true);
  FastLED.show();
  delay(1000);

  while(!RGB_sensor.init()){                                // Initialize the ISL29125 with simple configuration so it starts sampling
    Serial.println("trying to start the sensor!");
    delay(50);
  }
  Serial.println("Sensor Initialization Successfulnr");
}

void loop() {
  /* Begin Taking a Reading */

  sensorPower(true);                // Turn on the sensor  
  setLED(200, 200, 255);            // Turn on the LED to illuminate the subject area
  FastLED.show();                   // ^- adjust the balance of white here... blue seems to need some help (higher Vf than other leds..)

  delay(2);                         // some time for sensor to come online
  RGB_sensor.init();                // now perform initialization since the sensor had been asleep

  delay(200); // sensor continuously runs ADC at ~ 10 hz so to be sure wait 0.2 seconds before reading

  delay(300); // delay to combat voltage sag from turning on all the leds...
              // I've experimentally determined that while there is no LED brightness that completely 
              // eliminates noise in detected color there is a minimum total delay between turning on
              // the leds and taking a sample that gets darn close. Its approx 500 ms total (including
              // time dedicated to letting the sensor read)

              // the final product may as well turn on all the leds, wait half a second, and then sample
              // all of the color sensors rapidly. 


  red = RGB_sensor.readRed();     // Sample the sensor
  green = RGB_sensor.readGreen();
  blue = RGB_sensor.readBlue();


  sensorPower(false);             // Turn off the sensor
  setLED(0, 0, 0);                // Turn off the LED
  FastLED.show();                 // Apply changes to the 'LED' data (includes WS2811 'switch' changes)

                                  // Now let's try to sample the sensor to show that it has really been shut down
  delay(1);                       // Time for the sensor VDD line to fall to 0
  RGB_sensor.init();
  RGB_sensor.readRed();
  RGB_sensor.readGreen();
  RGB_sensor.readBlue();

  printResults();                 // Show the results on the Serial monitor

  delay(200);                     // delay 200 ms before taking another reading
}

void sensorPower(bool on){
  LEDS.setBrightness(255);                                  // Ensure full brightness so that WS2811 controls are not scaled

  if(on){
    leds[0] = CRGB(0, 0, 0);                                // Turn on the sensor by writing a 0 value to the R channel
  }else{
    leds[0] = CRGB(255, 0, 0);                              // Turn off the sensor by writing 255 to the red channel
  }
}

void setLED(uint8_t R, uint8_t G, uint8_t B){
  leds[1] = CRGB(R, G, B);                                  // The LED is the second item in the 'led' array (the first is the WS2811 sensor switch)
}



/*********************/
/* UTILITY FUNCTIONS */

float max3( float Rp, float Gp, float Bp, uint8_t* index ){
  // hacky way to find maximum of three (not tested well or even well-thought-through)...
  float Cmax = 0.0;
   if(Rp >= Gp){
      if(Rp >= Bp){
        Cmax = Rp;
        *index = 0;
      }
    }
    if(Gp >= Bp){
      if(Gp >= Rp){
        Cmax = Gp;
        *index = 1;
      }
    }
    if(Bp >= Gp){
      if(Bp >= Rp){
        Cmax = Bp;
        *index = 2;
      }
    }
    return Cmax;
}

float min3( float Rp, float Gp, float Bp, uint8_t* index ){
  // hacky way to find minimum of three (not tested well or even well-thought-through)...
  float Cmin = 0.0;
   if(Rp <= Gp){
      if(Rp <= Bp){
        Cmin = Rp;
        *index = 0;
      }
    }
    if(Gp <= Bp){
      if(Gp <= Rp){
        Cmin = Gp;
        *index = 1;
      }
    }
    if(Bp <= Gp){
      if(Bp <= Rp){
        Cmin = Bp;
        *index = 2;
      }
    }
    return Cmin;
}

void printResults( void ){
    float Rp = (float)red/255;
    float Gp = (float)green/255;
    float Bp = (float)blue/255;

    uint8_t max_ind = 0;
    uint8_t min_ind = 0;
    float Cmax = max3(Rp, Gp, Bp, &max_ind);
    float Cmin = min3(Rp, Gp, Bp, &min_ind);
    float delta = Cmax - Cmin;

    float hue = 0.0;
    if(Cmax == 0.0){
      hue = 0.0;
    }else{
      switch(max_ind){
        case 0: hue = 60 * (fmod(((Gp-Bp)/delta), 6.0)); break;
        case 1: hue = 60 * (((Bp-Rp)/delta) + 2); break;
        case 2: hue = 60 * (((Rp-Gp)/delta) + 4); break;
        default: break;
      }
    }

    // search list of colors for the closest one 
    //  (todo: when overall lux levels are low just say nothing is there)
    const char* identified_color = NULL;
    float prev_diff = 360.0;                              // start with a high (impossibly so) difference
    float diff = 0.0;
    uint8_t num_colors = sizeof(colors)/sizeof(color_t);
    for(uint8_t indi = 0; indi < num_colors; indi++){     // loop through all the named colors
      diff = abs(hue - colors[indi].hue);                     // find the difference between the selected color hue and the calculated hue
      if ( diff >= 180.0 ){                                   // correct for differences over 180 degrees because the spectrum is circular
        diff = 360.0 - diff;
      }
      if( diff < prev_diff ){                                 // if this difference is smaller change the detected color to this name
        prev_diff = diff;
        identified_color = colors[indi].name;
      }
    }

#if DISPLAY_RGB
#if DISPLAY_TITLES
    Serial.print("B: "); 
#endif
    Serial.print(blue);
    Serial.print(" ");

#if DISPLAY_TITLES
    Serial.print("R: "); 
#endif
    Serial.print(red);
    Serial.print(" ");

#if DISPLAY_TITLES
    Serial.print("G: "); 
#endif
    Serial.print(green);
    Serial.print(" ");
#endif

#if DISPLAY_HUE
#if DISPLAY_TITLES
    Serial.print("Hue: ");
#endif
    Serial.print(hue);
    Serial.print(" ");
#endif

#if DISPLAY_COLOR
#if DISPLAY_TITLES
    Serial.print("Color: ");
#endif
    Serial.print(identified_color);
    Serial.print(" ");
#endif

    Serial.println();
}

Usando um analisador de lógica digital, consegui gravar ótimos dados. Você pode ver que o tempo de subida da linha VDD do sensor corresponde ao esperado da simulação, bem como as mesmas pequenas ondulações quando o sensor é desligado. Você também pode ver que o sensor responde às transações I2C enquanto está ligado. Logo após o envio do comando 'off', a linha VDD cai e o sensor não responde mais às transações I2C. Isso sugere que desligar os sensores não utilizados deve ser suficiente para permitir o uso de mais de um sensor no mesmo barramento I2C.

Analisador lógico digital traço da linha VDD do sensor e transações I2C

Considerações adicionais

Este projeto é um trabalho em andamento. Escalar esse teste único até uma matriz de 192 nós apresentará mais desafios, como:

  • Velocidade da amostra - o teste acima não deixa tempo para o sensor fazer conversões ADC, portanto as leituras são iguais a 0. Na realidade, cada sensor precisará estar ligado por 100 a 200 ms para obter uma boa amostra.
  • Capacitância de barramento I2C - geralmente é desafiador usar o I2C em longas distâncias devido à topologia de dreno aberto.

Esses desafios provavelmente impedirão o uso desse método no projeto Floresta Arco-Íris. Ainda assim, o uso do WS2811 de maneiras criativas pode ser útil em vários projetos que já envolvem LEDs endereçáveis, como layouts de modelos de trem, shows de DIY com efeitos especiais e muito mais!

Se você usar o WS2811 em um projeto próprio, informe-nos!

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br