Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 22 of 22

Thread: looking for ideas on generating RGB colors from accelerometer + gyroscope

  1. #1
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82

    looking for ideas on generating RGB colors from accelerometer + gyroscope

    Hi all, I'm fairly new to Arduino / Teensy but I do have a background in computer science and some electronics, from my studies long ago.

    I'm working on a toy with addressable LEDs that I want to have change colors based on output from an accelerometer and a gyroscope. I have these in one MPU 6050 unit now and I'm able to read raw data, like so:

    a/g: -1240 -2460 15652 48 -218 -363
    a/g: -1200 -2468 15512 48 -257 -359
    a/g: -1096 -2568 15600 40 -207 -363
    [...]

    These are accelerometer x,y,z and then gyroscope x,y,z. I understand what these values mean, but I want to make some nice color shifts with them, so that if you do this or that movement with the toy, you get a corresponding cool / fluid change in colors. I've already done this with just the accelerometer numbers of a different unit (ADXL345) and that seemed fairly straightforward. I didn't like the noisyness of it, but I suppose filters can solve that issue.

    What I'm looking for is ideas for algorithms that I can let loose here, to create RGB colors, which can be 8 bits per color as I'm using a WS2801 LED strip. Since I now have 6 values to mix up it's getting a bit much. I'm not that good at math so perhaps anyone can help me out here with some formulas to try.

    Thanks!

  2. #2
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    Ok, so here's the first result of some experimentation:

    http://www.youtube.com/watch?v=p39Td...ature=youtu.be

  3. #3
    Member
    Join Date
    Jan 2013
    Location
    Salem, MA
    Posts
    46
    Do they spin fast enough to produce POV effect that you could use with strobed patterns (or even lettering, you have enough pixels)? Fast strobing is easy and fun. Maybe you can refresh fast enough to send quick pulses along the strip at certain speeds.

    I haven't used a gyro. But wanted to try spin-based POV using an accelerometer. I think from some tests I made with nunchuks a while back, the |x^2 + y^2 + z^2| seems to give a smooth curve that follows swinging. But in the nunchuk case the accelerometer signals clipped at very low G's.

    If you don't mind a bit of math, this app note has the equations to calculate pitch & roll,
    http://www.freescale.com/files/senso...ote/AN3461.pdf
    or, in 'C', if ax is acceleration on the X axis and ax2 is ax*ax,
    tiltX = atan(ax/sqrt(ay2+az2))*radToDegrees;
    tiltY = atan(ay/sqrt(ax2+az2))*radToDegrees;
    tiltZ = atan(sqrt(ay2+ax2)/az)*radToDegrees;

  4. #4
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    You can't really see it in the video, but I am doing some very basic POV using some simple update algorithm. The result:



    In psuedo code, I am doing:

    10 retrieve color value based on gyro or accelero reading
    20 "colorWipe" from ends of staff to middle with that color, with a few ms in between each pixel.
    30 wait 5ms
    40 "colorWipe" from ends of staff to middle with no color (lights off), with a few ms in between pixels.

    "colorWipe" is a function that updates the pixels one by one in order. You can tell it to wipe from the middle to the ends, from the ends to the middle, or from one end to the other.

    An alternative to the above is to use the other colorWipe modes, so instead of getting a star shape POV "cutout" like above, you get a star shape formed by the LEDs, instead, if you colorWipe from the middle to the outside. I now have 8 pixels on each side of the staff. Each pixels is 3 LEDs that are spaced 120 degrees apart, around the staff, for maximum visibility. I would like to pack more pixels in so I've ordered a WS2811 strip with 60 LEDs per meter, instead of the 32 I have now.

    Thanks for the math! I am not good in math so I welcome getting any formulas to put into code. The values of the accelero and gyro are unsigned 16 bit numbers. I think I can probably set the G sensitivity but haven't found yet. However I'm not that easily clipping. What I am doing now to get colors out of the readings is this:

    Code:
    	// convert these 16 bit signed integers to something we can make colors out of
    
    	// raw values can be positive or negative, depending on which direction 
    	// the axis is going. Let's use the same color for the same force in both 
    
    	// turn into positive-only value, as we can't generate negative colors.
    	// accelero values
    	uint16_t ax_abs = abs(ax);
    	uint16_t ay_abs = abs(ay);
    	uint16_t az_abs = abs(az);
    	// gyro values
    	uint16_t gx_abs = abs(gx);
    	uint16_t gy_abs = abs(gy);
    	uint16_t gz_abs = abs(gz);
    
            // we scale down to 8 bit numbers, as the 3 colors are 8 bits each.
    	if (gyro) {
    		red_uint8 = gx_abs / 128;
    		green_uint8 = gy_abs / 128;
    		blue_uint8 = gz_abs / 128;
    	} else {
    		red_uint8 = ax_abs / 128;
    		green_uint8 = ay_abs / 128;
    		blue_uint8 = az_abs / 128;
    	}
    
    	*red = red_uint8;
    	*green = green_uint8;
    	*blue = blue_uint8;
    
    	// cancel out some noise
    	*red < 4 ? *red = 0 : 1 ;
    	*green < 4 ? *green = 0 : 1 ;
    	*blue < 4 ? *blue = 0 : 1 ;
    So this is very basic, but I would like to see if I can make the transitions more smooth.
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	img3029o.jpg 
Views:	406 
Size:	234.9 KB 
ID:	189  
    Last edited by neep; 01-25-2013 at 01:29 PM.

  5. #5
    Senior Member Wozzy's Avatar
    Join Date
    Jan 2013
    Location
    Philadelphia, Pennsylvania USA
    Posts
    307
    Thanks for sharing the video...That looks like a fun project.

    One idea might be to have different colored LEDs simulate marbles in the tube.
    When you spin, the colors all go out to the ends, and become denser at the ends.
    If you shake it back and forth, the colors would rattle back and forth.

    Another, would be to change color, or intensity with the rate of rotation
    spike in acceleration, could initiate an explosion in color


    I ordered 20m of 68/m ws2811 lightstrips and just the other day ordered a gy-80 IMU like this one on eBay for $16.00

    It should be fun

  6. #6
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    Hey Wozzy thanks for your suggestions. With the gyro based colorWipe modes, I'm already getting more intense colors as I spin / change angle faster now. When I hold the staff still it dims more, and is totally dimmed when I lay it down, so that's to be expected behaviour with a gyro.

    As for the "marbles" idea, I really like that one. I'll see if I can implement something like that.

    I would also like to do bitmap based POV, but don't have any code for that yet. I also need some extra memory if I'm going to be using bigger images, but I should be fine with say 10kB images for now, or just some characters to write with. I'm a little worried that 8 pixels per side isn't going to be enough, but it's a start until I get the higher density strips. Those may require more battery power anyway. I only have about 1200mAh available now.

    If anyone has some drop-in POV (test) code for bitmaps that I can use or convert that would be highly appreciated!

    BTW keep me posted on the 68 LEDs/m strips you ordered.

    And I am using a GY-521 MPU 6050 module, like here described here: http://playground.arduino.cc/Main/MPU-6050

    It was less than $10. I see the GY-80 has a compass and barometer probably making it more expensive. I doubt I need that anyway.
    Last edited by neep; 01-25-2013 at 01:55 PM.

  7. #7
    Member
    Join Date
    Jan 2013
    Location
    Salem, MA
    Posts
    46
    Nice!

    If you're having problems with noisy data from the accel readings, one technique I find works pretty reliably is a "moving-average" filter, like this
    Code:
    long avg_value;
    loop{
    // add the new value to the moving average
    avg_value = ( ( avg_value * 4 ) + new_value ) / 5
    }
    where a lower ratio (19/20, etc, instead of 4/5) increases the amount of smoothing.

  8. #8
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    Good one! I just tried this and it does help for the accelerometer. For the gyro I find it not that interesting as that's about sudden changes that I want to have reflect in the colors or at least the intensity anyway. I am now thinking I could use a mix: the accelerometer output for the color mix, and the gyro output for the overal brightness of the colors. I need to do some bitshifting logic to make that all happen, as I need to come up with a 24 bit number every time (8 bits per RGB color).

  9. #9
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    I've been coding for quite some hours through the night, and finally have a reasonably decent POV output, with some characters. The result:


  10. #10
    Senior Member Wozzy's Avatar
    Join Date
    Jan 2013
    Location
    Philadelphia, Pennsylvania USA
    Posts
    307

    Nice!

    Quote Originally Posted by neep View Post
    I've been coding for quite some hours through the night, and finally have a reasonably decent POV output, with some characters. The result:...
    Excellent work!!! You've got a real knack for this.

    I hope you got some sleep.... I do the same thing once I get my head into a fun project, I can't stop.

    Once I get those new light strips, and the IMU, I'd love to play some with your code.
    Last edited by Wozzy; 01-26-2013 at 05:15 PM.

  11. #11
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    Thanks

    Now I want to be able to display bitmaps using RGB coloring. 8 pixels per side is a bit limited, but a 4m 60LED/m 2811 strip is on the way. First I have to figure out how to read from the micro SD adapter I got from PJRC, or maybe upload bitmaps via bluetooth. All I can do with bluetooth now is very basic serial communications. What I have now is a few characters bitmapped as bool[]s, so it's lots of manual labor to add more. I rather do that with a little pixel editor app.

  12. #12
    Junior Member
    Join Date
    Feb 2013
    Posts
    19
    Sorry I'm late to the party on this. I might have an interesting approach for you. Your color changing might be much more fluid and natural if you convert from RGB to something more intuitive like HSV color space. If you are unfamiliar with HSV, it is slightly more visually intuitive than RGB for color representation, once you understand the model. Here is a brief explanation:
    http://en.wikipedia.org/wiki/HSL_and_HSV

    You could use per axis adjustments to change hue/saturation/brightness or something similar. I'm appending a library I wrote for a current project that you might find useful. It stores color as HSV, but then will return it as RGB when needed to send to the LED pins. It's currently configured for 255 scale RGB values, but you could easily change that to your needs. I've had great success using this so far and it's a lot easier to set custom colors using rotary faders and the like with HSV space instead of RGB (which most people don't find intuitive). Of course, this is beta, mostly undocumented and only lightly tested, but I know the conversion stuff works like a charm. Also, please don't ask why I decided to implement my own version of floor(). I'm pretty sure I was drunk at the time. Let me know if it's helpful at all!

    HEADER
    Code:
    /*
      Color.h - Library for controlling RGB arcade buttons
      Created by Jesse R. Castro 2013-02-03
    */
    #ifndef Color_h
    #define Color_h
    
    #include "Arduino.h"
    #include <Common.h>
    
    class Color
    {
      public:
    	//public vars
    	
        //constructor
    	Color(float pHue, float pSaturation, float pValue);
    	Color(const Color& pColor);
            Color();
        //destructor
    	
    	//setters
    	void setHue(float pHue);
    	void setSaturation(float pSaturation);
    	void setValue(float pValue);
    	void setHSV(float pHue, float pSaturation, float pValue);
    	//getters
    	float getHue() const;
    	float getSaturation() const;
    	float getValue() const;
    	int getRed();
    	int getBlue();
    	int getGreen();
    	//action methods
    	void turnOff();	
    	//operator overloads
    	Color& operator=(const Color &pColor);
    	bool operator==(const Color &pColor) const;
    	bool operator!=(const Color &pColor) const;
    private:
        //private vars
    	int red;
    	int green;
    	int blue;
    	float hue;
    	float saturation;
    	float value;
    	//setters
    	void setRed(int pRed);
        void setGreen(int pGreen);
    	void setBlue(int pBlue);
    	void setRGB(int pRed, int pBlue, int pGreen);
    	//getters
    	
    	//action methods
    	
    	//utilities
    	void rgb2hsv();
    	void hsv2rgb();
    	float getMin();
    	float getMax();
    	int floor(float target);
    };
    
    #endif
    IMPLEMENTATION
    Code:
    /*
      Color.cpp - Library for controlling RGB arcade buttons
      Created by Jesse R. Castro 2013-02-03
    */
    
    #include "Color.h"
    
    Color::Color(float pHue, float pSaturation, float pValue){
    	setHSV(pHue, pSaturation, pValue);
    }
    Color::Color(const Color& pColor){
    	*this = pColor;
    }
    Color::Color(){
    	setHSV(0,0,0);
    }
    //setters
    void Color::setHue(float pHue){
    	//Note, of these hue cycles, so we have to make sure that works
    	//abs gets rid of any negatives
    	//the val - floor(val) will take return only decimal portions
    	hue = abs(pHue) - floor(abs(pHue));
    	
    }
    void Color::setSaturation(float pSaturation){
    	if(pSaturation < 0){
    		saturation = 0;
    	}else if(pSaturation > 1){
    		saturation = 1;
    	}else{
    		saturation = pSaturation;
    	}
    }
    void Color::setValue(float pValue){
    	if(pValue < 0){
    		value = 0;
    	}else if(pValue > 1){
    		value = 1;
    	}else{
    		value = pValue;
    	}
    }
    void Color::setHSV(float pHue, float pSaturation, float pValue){
    	setHue(pHue);
    	setSaturation(pSaturation);
    	setValue(pValue);
    }
    void Color::setRed(int pRed){
    	if(pRed < 0){
    		red = 0;
    	}else if(pRed > 255){
    		red = 255;
    	}else{
    		red = pRed;
    	}
    }
    void Color::setBlue(int pBlue){
    	if(pBlue < 0){
    		blue = 0;
    	}else if(pBlue > 255){
    		blue = 255;
    	}else{
    		blue = pBlue;
    	}
    }
    void Color::setGreen(int pGreen){
    	if(pGreen < 0){
    		green = 0;
    	}else if(pGreen > 255){
    		green = 255;
    	}else{
    		green = pGreen;
    	}
    }
    void Color::setRGB(int pRed, int pGreen, int pBlue){
    	setRed(pRed);
    	setGreen(pGreen);
    	setBlue(pBlue);
    }
    //getters
    float Color::getHue() const{
    	return hue;
    }
    float Color::getSaturation() const{
    	return saturation;
    }
    float Color::getValue() const{
    	return value;
    }
    int Color::getRed(){
    	hsv2rgb();
    	return red;
    }
    int Color::getGreen(){
    	hsv2rgb();
    	return green;
    }
    int Color::getBlue(){
    	hsv2rgb();
    	return blue;
    }
    
    //action methods
    void Color::turnOff(){
    	setValue(0);
    }
    void Color::rgb2hsv(){
    	float r = (red + 0)/255.0;
    	float g = (green + 0)/255.0; 
    	float b = (blue + 0)/255.0;
    			
    	float max = max(max(r, g), b);
    	float min = min(min(r, g), b);
    	
    	float h = max;
    	float s = max;
    	float v = max;
    
    	float d = max - min;
    	s = max == 0 ? 0 : d / max;
    
    	if(max == min){
    		h = 0; // achromatic
    	}else{
    		if(max == r){
    			h = (g - b) / d + (g < b ? 6 : 0);
    		}else if (max == g){
    			h = (b - r) / d + 2; 
    		}else{
    			h = (r - g) / d + 4; 
    		}
    		h /= 6;
    	}
    
    	setHue(h);
    	setSaturation(s);
    	setValue(v);
    }
    void Color::hsv2rgb(){
    	float r, g, b;
    
    	float h = hue;
    	float s = saturation;
    	float v = value;
    	
    	int i = floor(h * 6);	
    	float f = h * 6 - i;
    	float p = v * (1 - s);
    	float q = v * (1 - f * s);
    	float t = v * (1 - (1 - f) * s);
    
    	switch(i % 6){
    		case 0: r = v, g = t, b = p; break;
    		case 1: r = q, g = v, b = p; break;
    		case 2: r = p, g = v, b = t; break;
    		case 3: r = p, g = q, b = v; break;
    		case 4: r = t, g = p, b = v; break;
    		case 5: r = v, g = p, b = q; break;
    	}
    
    	setRed(round(r*255));
    	setGreen(round(g*255));
    	setBlue(round(b*255));
    	
    }
    float Color::getMin(){
    	float r = (red + 0)/255.0;
    	float g = (green + 0)/255.0;
    	float b = (blue + 0)/255.0;
    	
    	if(r < g){
    		if(r < b){
    			return r;
    		}else{
    			return b;
    		}
    	}else{
    		if(g < b){
    			return g;
    		}else{
    			return b;
    		}
    	}
    }
    float Color::getMax(){
    	float r = (red + 0)/255.0;
    	float g = (green + 0)/255.0;
    	float b = (blue + 0)/255.0;
    	
    	if(r > g){
    		if(r > b){
    			return r;
    		}else{
    			return b;
    		}
    	}else{
    		if(g > b){
    			return g;
    		}else{
    			return b;
    		}
    	}
    }
    int Color::floor(float target){
    	int returnVal = round(target);
    	if(returnVal > target){
    		returnVal--;
    	}
    	return returnVal;
    }
    //operator overloads
    Color& Color::operator=(const Color &pColor){
    	setHSV(pColor.hue, pColor.saturation, pColor.value);	
    	return *this;
    }
    
    /** 
     * Comparison == operator overload.
     * @author Jesse R. Castro
     * @param pFoo An instance of the same type as this object.
     * @return A boolean value describing whether the objects are equivalent or not.
     */
    bool Color::operator==(const Color &pColor) const {
    	if(
    		(hue == pColor.hue) &&
    		(saturation == pColor.saturation) &&
    		(value == pColor.value)
    	){
    		return true;
    	}else{
    		return false;
    	}
    }
    /** 
     * Comparison != operator overload.
     * @author Jesse R. Castro
     * @param pFoo An instance of the same type as this object.
     * @return A boolean value describing the inverse of whether the objects are equivalent or not.
     */
    bool Color::operator!=(const Color &pColor) const {
    	return !(*this == pColor);
    }

  13. #13
    Senior Member ZTiK.nl's Avatar
    Join Date
    Dec 2012
    Location
    Amsterdam
    Posts
    179
    You probably already got it done, but in case you didn't, maybe this can help too:

    My 2.8" TFT screen contains an arduino code example to draw BMP files from SD to the screen, reading a preset amount of pixels and push them to the screen.
    The default example can be found here, but I managed to convert it to use the new and improved SdFat library which can be found here (I mean the modified code, not the SdFat)

    Not really written for POV, but I'm sure you can modify it to light LED's instead of display on screen.
    I do have to mention that this only works for 24bit BMP's according to the README file...

  14. #14
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    Hey aedile thanks for this idea, I think it may be very helpful and I want to implement it. I've copied your code but I'm missing your Common.h:

    In file included from Color.ino:6:0:
    Color.h:9:20: fatal error: Common.h: No such file or directory
    compilation terminated.

    I removed the dependency on that and it compiles fine. I'm good without it?

    Also, could you please give me an example of how your use your code from my main loop? I'm not a very experienced coder.

    Thanks,

    neep
    Last edited by neep; 11-05-2013 at 11:17 PM.

  15. #15
    Senior Member MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    2,278
    Just a note, if you need every last drop of microprocessor processing power, the HSV library does everything in the float data type. The Teensy 3.0/2.0++/2.0, and the Arduinos all do not have floating point hardware. This means it will take several hundreds of instructions to simulate most floating point, and probably thousands of instructions to simulate divide. A lot of time, that doesn't matter, as the microprocessor might spend most of its time waiting for something to happen. But if you are trying to display lots of colors in real time, it might cause your code to run slowly.

  16. #16
    Senior Member
    Join Date
    Jan 2013
    Posts
    964
    Or completely in integer format:

  17. #17
    Senior Member
    Join Date
    Jan 2013
    Posts
    964

    HSV to RGB in integer

    Both of these algorithms do HSV to RGB in integer only. The first one is speed optimized for 8bit, the second one provides smoother blending due to the higher resolution for "index" and may not be quite as speedy. On a Teensy3 it may not make much of a difference.

    Code:
    /*
    HSV 0..255
    */
    void HPRGB::goToHSB(uint8_t hue, uint8_t saturation, uint8_t value)
    {
      uint8_t r, g, b;
      HSBtoRGB(hue, saturation, value, &r, &g, &b);
      goToRGB(r, g, b);
    }
    
    void HPRGB::HSBtoRGB(uint8_t h, uint8_t s, uint8_t v, uint8_t* r, uint8_t* g, uint8_t* b)
    {
    
            if ( s == 0 )
            {
                    *b = *g = *r = v;
            }
            else
            {       
                    
                    uint8_t i = (h*6)/256;
                    uint16_t f = (h*6) % 256;
    
                    uint16_t p = (v * (255 - s)) / 256;
                    uint16_t q = (v * (255 - (s * f)/256)) / 256;
                    uint16_t t = (v * (255 - (s * (255 - f))/256)) / 256;
    
                    if      ( i == 0 ) { *r = v ; *g = t ; *b = p; } // 0   deg (r)   to 60  deg (r+g)
                    else if ( i == 1 ) { *r = q ; *g = v ; *b = p; } // 60  deg (r+g) to 120 deg (g)
                    else if ( i == 2 ) { *r = p ; *g = v ; *b = t; } // 120 deg (g)   to 180 deg (g+b)
                    else if ( i == 3 ) { *r = p ; *g = q ; *b = v; } // 180 deg (g+b) to 240 deg (b)
                    else if ( i == 4 ) { *r = t ; *g = p ; *b = v; } // 240 deg (b)   to 300 deg (b+r)
                    else               { *r = v ; *g = p ; *b = q; } // 300 deg (b+r) to 0   deg (r)
            }
    
    }
    Code:
    /*
    HSV 0-768
    */
    void HPRGB::goToHSB16(uint16_t hue, uint8_t saturation, uint8_t value)
    {
    	uint8_t r, g, b;
    	HSBtoRGB16(hue, saturation, value, &r, &g, &b);
    	goToRGB(r, g, b);
    }
    
    void HPRGB::HSBtoRGB16(uint16_t index, uint8_t sat, uint8_t bright, uint8_t* r, uint8_t* g, uint8_t *b  )
    {
    	uint16_t r_temp, g_temp, b_temp;
    	uint8_t index_mod;
    	uint8_t inverse_sat = (sat ^ 255);
    	
    	index = index % 768;
    	index_mod = index % 256;
    	
    	if (index < 256)
    	{
    		r_temp = index_mod ^ 255;
    		g_temp = index_mod;
    		b_temp = 0;
    	}
    	
    	else if (index < 512)
    	{
    		r_temp = 0;
    		g_temp = index_mod ^ 255;
    		b_temp = index_mod;
    	}
    	
    	else if ( index < 768)
    	{
    		r_temp = index_mod;
    		g_temp = 0;
    		b_temp = index_mod ^ 255;
    	}
    	
    	else
    	{
    		r_temp = 0;
    		g_temp = 0;
    		b_temp = 0;
    	}
    	
    	r_temp = ((r_temp * sat) / 255) + inverse_sat;
    	g_temp = ((g_temp * sat) / 255) + inverse_sat;
    	b_temp = ((b_temp * sat) / 255) + inverse_sat;
    	
    	r_temp = (r_temp * bright) / 255;
    	g_temp = (g_temp * bright) / 255;
    	b_temp = (b_temp * bright) / 255;
    	
    	*r = (uint8_t)r_temp;
    	*g = (uint8_t)g_temp;
    	*b = (uint8_t)b_temp;
    }

  18. #18
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    13,800
    Here's an integer one I wrote for one of OctoWS2811's examples.

    Code:
    // Convert HSL (Hue, Saturation, Lightness) to RGB (Red, Green, Blue)
    //
    //   hue:        0 to 359 - position on the color wheel, 0=red, 60=orange,
    //                            120=yellow, 180=green, 240=blue, 300=violet
    //
    //   saturation: 0 to 100 - how bright or dull the color, 100=full, 0=gray
    //
    //   lightness:  0 to 100 - how light the color is, 100=white, 50=color, 0=black
    //
    int makeColor(unsigned int hue, unsigned int saturation, unsigned int lightness)
    {
            unsigned int red, green, blue;
            unsigned int var1, var2;
    
            if (hue > 359) hue = hue % 360;
            if (saturation > 100) saturation = 100;
            if (lightness > 100) lightness = 100;
    
            // algorithm from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19
            if (saturation == 0) {
                    red = green = blue = lightness * 255 / 100;
            } else {
                    if (lightness < 50) {
                            var2 = lightness * (100 + saturation);
                    } else {
                            var2 = ((lightness + saturation) * 100) - (saturation * lightness);
                    }
                    var1 = lightness * 200 - var2;
                    red = h2rgb(var1, var2, (hue < 240) ? hue + 120 : hue - 240) * 255 / 600000;
                    green = h2rgb(var1, var2, hue) * 255 / 600000;
                    blue = h2rgb(var1, var2, (hue >= 120) ? hue - 120 : hue + 240) * 255 / 600000;
            }
            return (red << 16) | (green << 8) | blue;
    }
    
    unsigned int h2rgb(unsigned int v1, unsigned int v2, unsigned int hue)
    {
            if (hue < 60) return v1 * 60 + (v2 - v1) * hue;
            if (hue < 180) return v2 * 60;
            if (hue < 240) return v1 * 60 + (v2 - v1) * (240 - hue);
            return v1 * 60;
    }

  19. #19
    Member neep's Avatar
    Join Date
    Jan 2013
    Location
    Amsterdam, NL
    Posts
    82
    I haven't implemented any of the latest code suggestions yet, but I did make a video last night of what I have so far:

    http://www.youtube.com/watch?v=ob8jcgis0LU

    Basically what I'm doing is using each accelero + gyro axis to generate an 256 bit value for RGB. I'd like to reduce the "whiteness" when spinning fast, perhaps switching to HSV will do that for me.

  20. #20
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    725
    Quote Originally Posted by ZTiK.nl View Post
    You probably already got it done, but in case you didn't, maybe this can help too:

    My 2.8" TFT screen contains an arduino code example to draw BMP files from SD to the screen, reading a preset amount of pixels and push them to the screen.
    The default example can be found here, but I managed to convert it to use the new and improved SdFat library which can be found here (I mean the modified code, not the SdFat)

    Not really written for POV, but I'm sure you can modify it to light LED's instead of display on screen.
    I do have to mention that this only works for 24bit BMP's according to the README file...
    @ZTiK.nl, I've been looking into your code mods for reading 24bit bmp from sd card for tft screen. I have modified it to be blind to the screen, but to include octows2811 for output to led strip. I think that the section i need to alter is:

    if(lcdidx > 0) {
    tft.pushColors(lcdbuffer, lcdidx, first);
    }
    but this hangs the output (checking with Serial.print). Without adding in the leds.setPixel(…) ledsShow() lines, the output is:

    Initializing SD card...OK!
    Loading image 'circle.bmp'
    File opened.
    File size: 27174
    Image Offset: 54
    Header size: 40
    Bit Depth: 24
    Image size: 150x60
    Loaded in 79 ms
    0

    Any pointers would be useful. I have a feeling that buffer size needs to be looked at, and the fact that ws2811 are 24bit pixels and I think that this code is looking at 16bit pixel output ( is that correct?). The other section of the code that I have a query about is this:

    // Convert pixel from BMP to TFT format
    b = sdbuffer[buffidx++];
    g = sdbuffer[buffidx++];
    r = sdbuffer[buffidx++];
    lcdbuffer[lcdidx++] = tft.color565(r,g,b);

    I have commented out the lcdbuffer line to get the code to compile, but need to understand the tft.color565 argument.

    mortonkopf
    Last edited by mortonkopf; 11-08-2013 at 11:59 AM.

  21. #21
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    725
    in response to getting BMP images from SD card and then displaying in a POV, I have finally managed to get the Teensy 3 to read the SD card file using SDFat, and display to the POV using OctoWS2811. For a set of 60 leds it show the full bitmap of 60x150 in approx 290ms.

    the code the ZTik.nl pointed to was very useful. the changes were reasonably straight forward:

    Code:
                // set pixel
                b = sdbuffer[buffidx++];
                g = sdbuffer[buffidx++];
                r = sdbuffer[buffidx++];
    
                povbuffer[povidx++] = Color(b,g,r);//octo colour
              }
            for(int i=0;i<ledsPerStrip;i++){
       leds.setPixel(i, povbuffer[i]); }
            leds.show();
    I will post up the full code in a new thread to make it easy to find
    mortonkopf

  22. #22
    Junior Member
    Join Date
    Jun 2016
    Posts
    6
    I know it's been over 3 years on this, but do you guys by chance have any updated code that you ended up using?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •