Arduino und Neopixel: Kontrolle über App

Hi,
ich habe eine eigene Android App programmiert, um meine Neopixel zu steuern. Ich habe ein HC-05 Bluetooth Modul verbaut, um die Daten, die ich von der App sende, empfangen kann.

Was funktioniert?
Die Verbindung steht, Daten können gesendet werden.

Was nicht funktioniert?
RGB Farbdaten werden nicht korrekt angezeigt, obwohl ich per Serial Monitor gesehen hab, dass die jeweiligen Werte empfangen wurden.

Java Code der App:

void SendRGB() {
 if (btSocket != null) {
 //sendSignal("" + (65536 * red.getProgress() + 256 * green.getProgress() + blue.getProgress()));

 String redValue = String.format("%03d", red.getProgress());
 String greenValue = String.format("%03d", green.getProgress());
 String blueValue = String.format("%03d", blue.getProgress());

 String signal = redValue + greenValue + blueValue;

 sendSignal("s" + signal);
 }
}

Dieser Code nimmt 3 Werte von dem jeweiligen Rot-, Grün- und Blaureglern in meiner App. Dessen Werte befinden sich zwischen 0 und 255. Was dann letztendlich gesendet wird sieht so aus:

Beispiel:
Rot: 100
Grün: 1
Blau: 40

signal = 100001040

sendSignal = s100001040

Arduino Code: (Im Code sind Kommentare für euch gemacht)

#include <Adafruit_NeoPixel.h>

#include <SoftwareSerial.h>

int LED_COUNT = 5;//60;

int redValue = 0;
int greenValue = 0;
int blueValue = 0;

bool power = true;

Adafruit_NeoPixel strip(LED_COUNT, 6, NEO_GRB + NEO_KHZ800);

void setup() {
  //Serial.begin(38400);
  Serial.begin(9600);
  
  //strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
  strip.begin();
}

void loop(){
  char received[10];
  
  if (Serial.available() > 0) {
    int i = 0;
    while (Serial.available() > 0) {
      received[i] = Serial.read();
      Serial.write(received[i]); //<-------- Hier dran erkenne ich, dass alles richtig empfangen wird.
      
      i++;
    }
    
    if (received[0] == 's') { //<-------- Es leuchtet etwas, wenn ich den Knopf zum senden in meiner App drücke funktioniert diese Abfrage 
         redValue = (received[1] << 16) + (received[2] << 8) + received[3]; //<------- Hier werden die ersten 3 Zahlen (Im Beispiel 1 0 0) genommen und in eine ganze Zahl umgeformt, also 100
         greenValue = (received[4] << 16) + (received[5] << 8) + received[6]; //<-------- Hier werden die nächsten 3 Zahlen (Im Beispiel 0 0 4) genommen und in eine ganze Zahl umgeformt, also 
         blueValue = (received[7] << 16) + (received[8] << 8) + received[9]; //<------- U.s.w.
         strip.setPixelColor(0, strip.Color(redValue, greenValue, blueValue));

      }
      strip.show();
   }
}

Meiner Meinung nach vollkommen nachvollziehbar, jedoch funktioniert es nicht. Ich habe es auch schon mit einem direkten 32bit Color Integer versucht. Das hat aber leider auch nicht funktioniert...

Ich bedanke mich schonmal für euere Vorschläge.

Mit freundlichen Grüßen
Colin

received[1] << 16

das ist ein byte/char. Intern rechnet der UNO mit int. Wenn du den Inhalt 16 bit nach links shiftest fällt es sozusagen links raus. caste die Werte die du um 16 bits verschiebst auf uint32_t.

aber

wenn received[1] = 1 wie im Beispiel ist und die 1 um 16bit verschiebst erhähltst du sicher keine 100.

was du willst ist eher ein

received[1] *100 + received[2] *10 + received[3];

Kennst du WLED?
Nachdem ich das gesehen habe, habe ich das Rad nicht nochmal neu erfunden.

Lieben Gruß,
Chris

noiasca:
received[1] << 16

das ist ein byte/char. Intern rechnet der UNO mit int. Wenn du den Inhalt 16 bit nach links shiftest fällt es sozusagen links raus. caste die Werte die du um 16 bits verschiebst auf uint32_t.

aber

wenn received[1] = 1 wie im Beispiel ist und die 1 um 16bit verschiebst erhähltst du sicher keine 100.

was du willst ist eher ein

received[1] *100 + received[2] *10 + received[3];

Okay stimmt :o :confused:

Hab ich geändert. Nur ist jetzt das Problem, dass der Strip die ganze Zeit die selbe Farbe anzeigt, egal was für eine Eingabe ich mache.

themanfrommoon:
Kennst du WLED?
Nachdem ich das gesehen habe, habe ich das Rad nicht nochmal neu erfunden.

Lieben Gruß,
Chris

Mal von gehört aber ich weiß jetzt nicht genau, was ich damit anfangen soll?
Hier übrigens:
Mein Strip: BTF-LIGHTING WS2812B 5M 60 LEDs/Pixels/m 300LEDs RGB Schwarz PCB Streifen mit 5050 SMD LEDs NichtWasserdicht IP30: Amazon.de: Beleuchtung

Mal von gehört aber ich weiß jetzt nicht genau, was ich damit anfangen soll?

Tja, das kann das was du suchst, und noch 150 Sachen mehr. Das flashst du auf einen ESP8266 und bist in 5min fertig mit dem ganzen Thema.
Du musst also das Rad nicht nochmal erfinden. Das haben andere viel besser schon vor uns gemacht.

themanfrommoon:
Tja, das kann das was du suchst, und noch 150 Sachen mehr. Das flashst du auf einen ESP8266 und bist in 5min fertig mit dem ganzen Thema.
Du musst also das Rad nicht nochmal erfinden. Das haben andere viel besser schon vor uns gemacht.

Aber das bringt mir jetzt nichts mit meinem Arduino Uno und meinem vorhandenen Neopixel strip oder?

Hab ich geändert. Nur ist jetzt das Problem, dass der Strip die ganze Zeit die selbe Farbe anzeigt, egal was für eine Eingabe ich mache.

dann gib dir mal deine Input-Daten aus und deine Ergebnisse und vergleiche.

Das ganze char Array mit einer For schleife - jeden Wert als Hex ausgeben
und dann das Ergebnis.

So aus dem Bauch raus steht in received[1] nicht 1 sondern die ASCII Representation 49.
Vermutlich musst du daher erst mal 48 (=0x30) abziehen und dann erst mit 100 multiplizieren. Oder atoi() bemühen. Beim manuellen rechnen Klammern setzen nicht vergessen.

Mit entsprechenden Debug Ausgaben lassen sich auch Ablauffehler finden. Als reine Übung zum generellen Umgang von Variablen und zur effizenten Fehlersuche finde ich solche BlingBling Beispiele sehr gut. Also ruhig ein wenig üben.

noiasca:
dann gib dir mal deine Input-Daten aus und deine Ergebnisse und vergleiche.

Das ganze char Array mit einer For schleife - jeden Wert als Hex ausgeben
und dann das Ergebnis.

Mit entsprechenden Debug Ausgaben lassen sich Ablauffehler dann finden.

Habe ich nicht damit schon alles ausgegeben?

Serial.write(received[i]);

Und falls du das nicht meinst, wie kann ich das in Hexadezimal ausgeben?

verilyzed:
ich habe eine eigene Android App programmiert, um meine Neopixel zu steuern.

Auf einem ESP32 lasse ich Animationen für WS2812B/APA102/WS2815 laufen, die ich über eine Webseite mit JSON steuere, weshalb ich überlege, wie ich Dir helfen könnte.

Könnte ich Deine App irgendwie auf mein Smartphone bekommen?

Ich vermute, irgendein Steuerzeichen wie CR oder LF spuckt Dir in die Suppe, weshalb Du mal alle Zeichen, die Du empfängst, im seriellen Monitor in Hex anzeigen solltest. Deine Logik ist da nicht fehlerresistent. Besser wäre, Du wartest auf "s" und schreibst dann erst genau neun Zeichen in das Feld.

Upps, da war schon einer schneller.

Serial.print(received[i], HEX); Serial.print(' ');

agmue:
Auf einem ESP32 lasse ich Animationen für WS2812B/APA102/WS2815 laufen, die ich über eine Webseite mit JSON steuere, weshalb ich überlege, wie ich Dir helfen könnte.

Könnte ich Deine App irgendwie auf mein Smartphone bekommen?

Ich vermute, irgendein Steuerzeichen wie CR oder LF spuckt Dir in die Suppe, weshalb Du mal alle Zeichen, die Du empfängst, im seriellen Monitor in Hex anzeigen solltest. Deine Logik ist da nicht fehlerresistent. Besser wäre, Du wartest auf "s" und schreibst dann erst genau neun Zeichen in das Feld.

Upps, da war schon einer schneller.

Serial.print(received[i], HEX); Serial.print(' ');

Aber du hast geschrieben wie es geht :smiley:

Ich habe es implementiert. Als Ausgabe für "s255000000" hat er mir 73 32 35 35 30 30 30 30 30 30 ausgegeben.
Die App hab ich nur auf meinem Rechner. Irgendwo hochstellen könnte ich sie natürlich

(0x32 - 0x30) * 100 = 200
(0x35 - 0x30) * 10 = 50
(0x35 - 0x30) = 5

Summe 255.
Theorie ist gut. jetzt musst du es noch in Code umsetzen

noiasca:
(0x32 - 0x30) * 100 = 200
(0x35 - 0x30) * 10 = 50
(0x35 - 0x30) = 5

Summe 255.
Theorie ist gut. jetzt musst du es noch in Code umsetzen

Ich verstehe nicht ganz, wie ich das jetzt in den Code umsetzen kann :o :confused:

So hab ich es jetzt gemacht?

      redValue = (received[1] - '0') * 100 + (received[2] - '0') * 10 + received[3] -'0';

      greenValue = (received[4] - '0') * 100 + (received[5] - '0') * 10 + received[6] -'0';

      blueValue = (received[7] - '0') * 100 + (received[8] - '0') * 10 + received[9] -'0';

Aber das bringt mir jetzt nichts mit meinem Arduino Uno und meinem vorhandenen Neopixel strip oder?

WLED kann mindestens 10 verschiedene adressierbare LED Steifen und 17 verschiedene ESP Chips.
Was du draus machst ist jetzt dein Ding.
Das kommt ja auf dein Ziel drauf an.
Ist dein Ziel das Programmieren zu lernen musst du hier weitermachen.
Willst du ein mächtiges Werkzeug und willst wenig Zeit aufwenden um deine LEDs anzusteuern mach lieber mit WLED und einem ESP8266 weiter.

So hab ich es jetzt gemacht?

schaut doch soweit gut aus. Was macht es? Was macht es nicht?
Wenn du keine Erklärung hast, dann poste mal wieder einen vollständigen Code.

noiasca:
schaut doch soweit gut aus. Was macht es? Was macht es nicht?

Funktioniert leider nicht... :confused: Genau das selbe Ergebnis. Wenn ich z.B. strip.color(255, 0, 0) mache, dann zeigt er mir auch rot. Aber wenn dort nun Variabeln verbaut sind, die die Daten der App aufnehmen, geht es nicht.

wenn ich jetzt in der App 255 0 0 (R G B) einstelle und häuftiger senden drücke, flackert der strip und gibt ab und zu andere Farben aus. Manchmal sind die einzelnen LEDs sogar verschiedenfarbig ???? mit strip.fill() ist das doch eigentlich gar nicht möglich.

Mein Kompletter Code:

#include <Adafruit_NeoPixel.h>

#include <SoftwareSerial.h>

int LED_COUNT = 5;//60;

int redValue = 0;
int greenValue = 0;
int blueValue = 0;

bool power = true;

Adafruit_NeoPixel strip(LED_COUNT, 6, NEO_GRB + NEO_KHZ800);

void setup() {
  //Serial.begin(38400);
  Serial.begin(9600);
  
  //strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
  strip.begin();
}

void loop(){
  char received[10];
  
  if (Serial.available() > 0) {
    int i = 0;
    while (Serial.available() > 0) {
      received[i] = Serial.read();
      Serial.print(received[i], HEX); Serial.print(' ');
      i++;
    }
    
    if (received[0] == 's') {
      redValue = (received[1] - '0') * 100 + (received[2] - '0') * 10 + received[3] -'0';
      greenValue = (received[4] - '0') * 100 + (received[5] - '0') * 10 + received[6] -'0';
      blueValue = (received[7] - '0') * 100 + (received[8] - '0') * 10 + received[9] -'0';
      
      strip.fill(strip.Color(redValue, greenValue, blueValue), 0, LED_COUNT);
      power = true;
      
    } else if (received[0] == 'p') { 
      if (power) {
        strip.fill(strip.Color(0, 0, 0), 0, LED_COUNT);
        power = false;
      } else {
        strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
        power = true;
      }
    }
    strip.show();
  }
}

Ich hab neue Erkenntnisse!

Ich habe mir mit Serial.print() alle 3 values ausgegeben.

      Serial.print(redValue);

      Serial.print(greenValue);

      Serial.print(blueValue);

Jetzt kommt das verblüffende:
Jeder dieser Werte bleibt gleich, egal was für ein Wert ich über die App sende.
ROT GRÜN BLAU
6965 8812 5639

in deinen Variablen ist nicht das was du glaubst.
Mit ausreichend Serial.print Ausgaben sieht man das auch:

#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>

const uint16_t LED_COUNT = 5;     //60;
const uint8_t LED_PIN = 12;
uint8_t redValue = 0;
uint8_t greenValue = 0;
uint8_t blueValue = 0;

bool power = true;

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  //Serial.begin(38400);
  Serial.begin(9600);

  //strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
  strip.begin();
}

void loop() {
  char received[10];

  if (Serial.available() > 0) {
    int i = 0;
    memset(received,'\0', sizeof(received)); // löschen
    Serial.println();
    while (Serial.available() > 0) {
      received[i] = Serial.read();
      Serial.print(received[i], HEX); Serial.print(' ');
      i++;
    }
    Serial.println();
    if (received[0] == 's') {
      redValue = (received[1] - '0') * 100 + (received[2] - '0') * 10 + received[3] - '0';
      greenValue = (received[4] - '0') * 100 + (received[5] - '0') * 10 + received[6] - '0';
      blueValue = (received[7] - '0') * 100 + (received[8] - '0') * 10 + received[9] - '0';

      Serial.print(received[1], HEX); Serial.print(' '); Serial.print(received[2], HEX); Serial.print(' '); Serial.print(received[3], HEX); Serial.println();

      Serial.print(redValue); Serial.print("\t");
      Serial.print(greenValue); Serial.print("\t");
      Serial.print(blueValue); Serial.println();
      strip.fill(strip.Color(redValue, greenValue, blueValue), 0, LED_COUNT);
      power = true;

    } else if (received[0] == 'p') {
      if (power) {
        strip.fill(strip.Color(0, 0, 0), 0, LED_COUNT);
        power = false;
      } else {
        strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
        power = true;
      }
    }
    strip.show();
  }
}

dein Einlesen ist ein Käse.
Also arbeiten wir jetzt mal die Serial Input Basics durch und machen es dann vernünftig: Serial Input Basics - updated - Introductory Tutorials - Arduino Forum

noiasca:
in deinen Variablen ist nicht das was du glaubst.
Mit ausreichend Serial.print Ausgaben sieht man das auch:

#include <Adafruit_NeoPixel.h>

#include <SoftwareSerial.h>

const uint16_t LED_COUNT = 5;     //60;
const uint8_t LED_PIN = 12;
uint8_t redValue = 0;
uint8_t greenValue = 0;
uint8_t blueValue = 0;

bool power = true;

Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
 //Serial.begin(38400);
 Serial.begin(9600);

//strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
 strip.begin();
}

void loop() {
 char received[10];

if (Serial.available() > 0) {
   int i = 0;
   memset(received,'\0', sizeof(received)); // löschen
   Serial.println();
   while (Serial.available() > 0) {
     received[i] = Serial.read();
     Serial.print(received[i], HEX); Serial.print(' ');
     i++;
   }
   Serial.println();
   if (received[0] == 's') {
     redValue = (received[1] - '0') * 100 + (received[2] - '0') * 10 + received[3] - '0';
     greenValue = (received[4] - '0') * 100 + (received[5] - '0') * 10 + received[6] - '0';
     blueValue = (received[7] - '0') * 100 + (received[8] - '0') * 10 + received[9] - '0';

Serial.print(received[1], HEX); Serial.print(' '); Serial.print(received[2], HEX); Serial.print(' '); Serial.print(received[3], HEX); Serial.println();

Serial.print(redValue); Serial.print("\t");
     Serial.print(greenValue); Serial.print("\t");
     Serial.print(blueValue); Serial.println();
     strip.fill(strip.Color(redValue, greenValue, blueValue), 0, LED_COUNT);
     power = true;

} else if (received[0] == 'p') {
     if (power) {
       strip.fill(strip.Color(0, 0, 0), 0, LED_COUNT);
       power = false;
     } else {
       strip.fill(strip.Color(255, 255, 255), 0, LED_COUNT);
       power = true;
     }
   }
   strip.show();
 }
}




dein Einlesen ist ein Käse. 
Also arbeiten wir jetzt mal die Serial Input Basics durch und machen es dann vernünftig: https://forum.arduino.cc/index.php?topic=396450

Das ist ja alles schön und gut aber ich will ja eigentlich keine Serial Ausgabe haben. Ich möchte nur, dass die empfangen Daten auf 3 verschiedene Variablen (RGB) aufgeteilt werden und das dann auf meinem Strip die entsprechende Farbe angezeigt wird.

Das wollen wir doch alle :slight_smile:
Wenn es aber nun nicht gleich funktioniert sind serielle Ausgaben die (fast einzige) Möglichkeit herauszufinden wo es hakt.

wno158:
Das wollen wir doch alle :slight_smile:
Wenn es aber nun nicht gleich funktioniert sind serielle Ausgaben die (fast einzige) Möglichkeit herauszufinden wo es hakt.

Ich versuche mal ein paar Tipps aus diesem Tutorial zu entnehmen. Ich melde mich nachher nochmal falls etwas funktioniert :slight_smile: