Sending bytes with serial.write to arduino for neopixels

I just returned to a project where I am using a 60 LED neopixel strip to illuminate an aquarium.
I use a Raspberry Pi running a Python script which sends 3 bytes (RGB values) to an Arduino via serial.write. The Arduino then controls the neopixels.

This seems to work fine with the limited set of RGB values I had been using but recently I wanted to add a sunrise and sunset effect. There seems to be certain colour combinations that will alternately work as expected but on the next time of sending the values result in the LEDs lighting on full, as though I had sent 255;255;255.

A smaller test program I have been using to try to debug this is here:

import time
import serial #comms with Arduino
import struct
import datetime

ser = serial.Serial('/dev/ttyACM0', 9600)

#Give it a couple of seconds, sometimes seem to get connection issues.
print("initialising\n")
time.sleep(2)
Red = int(raw_input("Red?"))
Green = int(raw_input("Green?"))
Blue = int(raw_input("Blue?"))

values = [Red,Green, Blue]
string = ''
for i in values:
	string += struct.pack('>B',i)

#print(str(string))
print(':'.join(x.encode('hex') for x in string))# show contents of string for debugging
ser.write(string)

And the sketch is here:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#define PIN            6
#define NUMPIXELS      60
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(9600);          
  pixels.begin(); // This initializes the NeoPixel library.
}

int incomingByte = 0;  
int ColourVals[2];
int R =0;
int G =0;
int B =0;
void loop() {
//Serial.println("in loop");
  Serial.println(R);
  Serial.println(G);
  Serial.println(B);
 while (Serial.available()<3) {} // Wait 'till there are 3 Bytes waiting
    for(int n=0; n<3; n++)
      ColourVals[n] = Serial.read(); // Then: Get them.

  R=(int)ColourVals[0];
  G=(int)ColourVals[1];
  B=(int)ColourVals[2];

  for(int i=0;i<NUMPIXELS;i++){
    pixels.setPixelColor(i, R,G,B); }
    pixels.show();
  
}

So for example if I do this …

pi@aquariumpi:~ $ python colours.py
initialising

Red?0
Green?0
Blue?0
00:00:00
pi@aquariumpi:~ $

All of the LEDs come on full brightness, (the exact opposite of what is supposed to happen!) but if I do it again …

pi@aquariumpi:~ $ python colours.py
initialising

Red?0
Green?0
Blue?0
00:00:00
pi@aquariumpi:~ $

Then all of the LEDs go off, as they should do. I find this really perplexing!

I may re-do the project from start and get the Arduino to handle all of the colours, and use the Pi just for updating time and date from time to time which is fine but I did have dreams of linking the system to live weather updates one day which I think is more do-able with the set-up I have available.

Have you tried printing out the bytes as you receive them to see if they actually contain what you think they do?

while (Serial.available() < 3 ) {} // Wait 'till there are 3 Bytes waiting
But three hex digits will occupy 6 bytes.

And Serial.read( ) will only read one byte

I thought I was sending the data as binary bytes, just using hex to see what I'm sending in the terminal and I thought I was using serial read 3 times.( Sometimes what I think I am doing and what I'm actually doing are completely different)

There are bytes you can not put into a string because they are seen as string delimiters, just send the raw byte.

Thanks ... I may be going about this the wrong way but: I changed my Python code to this, below. Basically I (think I) am now just converting the int values directly to binary values. I am then sending those binary values with serial write.

On the arduino end of things my code is essentially unchanged. Monitoring the values of RGB that are coming it is receiving, serial monitor says 000 when that is what I have sent but the weird alternating behaviour of all lights full on and then all off on the next go continues.

I've also tried a few other sketches where I manually set values for RGB directly and have run the example "strandtest" programs and they seem to work fine.

It seems as though when I use serial.write in Python to send a value to the Arduino, even though doing a Serial.println tells me that the integer values it has received are what I expected them to be, it still displays incorrect colour values.

If there was something wrong with my approach below, please chip in.

In the meantime I think I will modify my approach and break a 24 hr day down into several thousand RGB values in an array. I will obtain a real time value for the Arduino and use that to calculate an index value and read off the corresponding RGB value.

import time
import serial #comms with Arduino
import struct
import datetime

ser = serial.Serial('/dev/ttyACM0', 9600)

#Give it a couple of seconds, sometimes seem to get connection issues.
print("initialising\n")
time.sleep(2)
Red = int(raw_input("Red?"))
Green = int(raw_input("Green?"))
Blue = int(raw_input("Blue?"))



values = [Red,Green, Blue]
#string = ''
for i in values:
    ser.write(struct.pack('>B',i))

I have tried the code in reply #18 on the raspberry Pi, talking to the Arduino code in the original post and it works as expected.

So what exactly is the problem? Is it with code you have not posted?

I have tried the code in reply #18 on

I’m confused (not lost, I know where I am). Yours was reply #6. Was there a typo there?

He claims that the code he posted in reply #18

morphy_richards: It seems as though when I use serial.write in Python to send a value to the Arduino, even though doing a Serial.println tells me that the integer values it has received are what I expected them to be, it still displays incorrect colour values.

So I tried that code and it worked fine. Mind you it only ran once so the Arduino would be resetting due to the serial port being enabled and disabled. So I put his code in a loop so there is no resetting and it works perfectly. Therefore i wonder what he means by "it still displays incorrect colour values".

EDIT - AH I see. Brain fart - not reply #18 at all but reply #5

Yes, it's very strange. The Python script converts an integer into a byte and sends it to the Arduino. The Arduino reads this, and apparently converts this back to an integer correctly. Checking the value of the integer in the serial monitor appears to confirm that the three integers I am sending from the external computer are received as the same integer values on the Arduino.

Using these 3 values to set an RGB value on the neopixel strip yields unexpected results.

Testing the neopixel strip using other integer values (which have not been transmitted from an external source, but are generated only on the arduino) works as expected.

I know that this must be due to my own error somewhere down the line, but I'm stumped as to where.

Are you using the right code? I ran the python on a Raspberry Pi and the C on an Arduino Uno. I only had a strip of 5 LEDs but that should not make any difference.

Could it be that whatever is sending your python is also adding things like line feed and carriage return, which you are not seeing in your testing but the Arduino is picking it up and using it for colour information?