I was working on putting together OSCars lighting system and of course I had to get my RGB led set up first. Several months back I was looking online for a better method to fade an LED. I cant remember where I found this or I would happily give the creator credit for it.
int periode = 5000;time = millis();value = 128+127*cos(2*PI/periode*time);
analogWrite(ledpin, value) ;
So basically what happens is once you reach 'value =' it maps that variable to a point on a wave. As the code loops that point will follow along the wave thanks to 'time=mills();' which uses the Arduinos built in running counter to make it both smooth as well as non-blocking.
The generated wave rises and falls symetrically and you can control the time from the start to the end of the wave by adjusting the 'periode' value. A value of 1000 will be about one second.
So with the following code you should be able to smoothly fade one led from minimum to full brightness back to minimum in 5 seconds...
const int ledpin = 13;
long time=0;
int periode = 5000;
int led_val = 0;
void setup() {
//nothing
}
void loop() {
rgbShow();
// Im going to run it as a function for ease of integration
analogWrite(ledpin, led_val)
//we will constantly write the value thats generated from the function to the ledpin
}
void rgbShow() {
time = millis();
value = 128+127*cos(2*PI/periode*time);
led_val = value;
}
But I want to use it with a full color LED!
So were just going to add two more variables called displace and displace2, these two values will offset the start of the wave - from the start of the first wave - by a value of milliseconds.
// declare before setup
int displace = 250;
int displace2 = 500;
//....setup()This will allow us to generate three waves for the three colors of our led.
void rgbShow() {
time = millis();}
value = 128+127*cos(2*PI/periode*time);
value2 = 128+127*cos(2*PI/periode*(displace-time));
value3 = 128+127*cos(2*PI/periode*(displace2-time));
redval = value;
greenval = value2;
blueval = value3;
Expirement with the values and see what you get!
Hey Paul,
ReplyDeletegreat work! Will you release the complete sketch with all the osc stuff? Its exactly what im searching for - but still stuck at the blocking for loop with delay :/
You can mail me if you like at nibelungen79 attt gmail.com
Best regards,
-andreas
Sure no problem- This sketch was actually written for an UNO w/ Arduino Motor Shield, also the functions to directly control the Red, Green, and Blue are not written in this version- for the video I just changed the values of the motor pins to match the RGB pins.
ReplyDeleteI keep the sketch separated into a few files and will post them the same way:
//**FILE1**//
ReplyDelete#define SOP '<'
#define EOP '>'
import processing.serial*;
bool started = false;
bool ended = false;
char inData[80];
byte index;
const int dirPinA = 13;
const int dirPinB = 12;
const int speedPinA = 3;
const int speedPinB = 11;
const int breakPinA = 9;
const int breakPinB = 8;
const int readPinA = A0;
const int readPinB = A1;
int speedA = 0;
int speedB = 0;
int dirA = 0;
int dirB = 0;
int breakA = 0;
int breakB = 0;
const int speed_limit = 255;
int speed_trim = 175;
int go_speed = 0;
int fspd_direction = 0;
int turn_rate = go_speed*.125;
String readString, sval, sval2, command, command_out; // used for values sent from serial in serialControl()
int command_value = 0;
int message = 0;
bool report_motors = false;
int motor_currency_a = 0;
int motor_currency_b = 0;
int value, value2, value3 ;
long time=0;
int displace = 250;
int displace2 = 500;
int periode = 5000;
int rgbshow_on;
void setup() {
Serial.begin(19200);
Serial.println("Hey There Buddy\n");
pinMode (dirPinA, OUTPUT);
pinMode (dirPinB, OUTPUT);
pinMode (speedPinA, OUTPUT);
pinMode (speedPinB, OUTPUT);
pinMode (breakPinA, OUTPUT);
pinMode (breakPinB, OUTPUT);
}
void loop() {
serialControl();
//Serial.println("finished serialControl()");
// WRITE TO YOUR PINS HERE (THEYRE CONTINUOUSLY BEING UPDATED BASED ON THE RESULTS OF DO_ME)
digitalWrite(dirPinA, dirA);
digitalWrite(dirPinB, dirB);
digitalWrite(breakPinB, breakB);
digitalWrite(breakPinA, breakA);
analogWrite(speedPinA, speedA);
analogWrite(speedPinB, speedB);
// Serial.println("finished writes");
heyMan();
// Serial.println("finished heyMan - End Loop");
}
//**FILE2 - SERIAL CONTROL **//
ReplyDeletevoid serialControl() {
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
// We are here either because all pending serial
// data has been read OR because an end of
// packet marker arrived. Which is it?
if(started && ended)
{
// The end of packet marker arrived. Process the packet
// Serial.println(inData);
// Serial.print(inData[index]);
readString += inData; //makes the string readString
// if (readString.length() >0) {
sval = readString.substring(0, 4);
sval2 = readString.substring(4, 7);
//
// Serial.print(sval);
// Serial.print(sval2);
int n1; //declare as number
int n2;
// char carray1[6]; //magic needed to convert string to a number
// sval1.toCharArray(carray1, sizeof(carray1));
char carray2[6];
sval2.toCharArray(carray2, sizeof(carray2));
n2 = atoi(carray2);
command_value = n2;
doMe();
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
//**FILE3 - DO_ME **//
ReplyDeletevoid doMe () {
/* MEAT AND POTATOS -
Here is where we map our OSC commands to values. The IF statements
Will match 4 character ´keys´ and their values sent by OSC
So in your OSC controller (TouchOSC in my case) you just name the
control something like ´trim´ - the Processing sketch will send
that and the value which is matched here
*/
/*
Serial.println(sval);
Serial.println(command_value);
*/
if(sval == "trim") {
speed_trim = map(command_value, 0, 255, 0, 255);
}
if(sval == "fbtn") {
fspd_direction = LOW;
}
if(sval == "rbtn") {
fspd_direction = HIGH;
}
if(sval == "read") {
int motorcurra = analogRead(A0)*2;
motor_currency_a = map(motorcurra, 0, 2046, 0, 1000);
int motorcurrb = analogRead(A1)*2;
motor_currency_b = map(motorcurrb, 0, 2046, 0, 1000);
reportMotors();
// if(command_value == 255) {
// report_motors = true;
// }
// else if(command_value == 0) {
// report_motors = false;
// }
}
if(sval == "lfwd") { // Left wheel forward
if(dirA == HIGH) {
speedA = 0;
}
adjustSpeed();
dirA = LOW;
speedA = go_speed;
}
if(sval == "lrvs") { //left wheel reverse
if(dirA == LOW) {
speedA = 0;
}
adjustSpeed();
dirA = HIGH;
speedA = go_speed;
}
if(sval == "rfwd") { // Right wheel forward
if(dirB == HIGH) {
speedB = 0;
}
adjustSpeed();
dirB = LOW;
speedB = go_speed;
}
if(sval == "rrvs") { // Right wheel reverse
if(dirB == LOW) {
speedB = 0;
}
adjustSpeed();
dirB = HIGH;
speedB = go_speed;
}
if(sval == "rotl") { // Rotate left
adjustSpeed();
dirA = HIGH;
dirB = LOW;
speedA = go_speed;
speedB = go_speed;
}
if(sval == "rotr") { // Rotate right
adjustSpeed();
dirA = LOW;
dirB = HIGH;
speedA = go_speed;
speedB = go_speed;
}
if(sval == "stop") { // Full Breaking
if(command_value == 255) {
breakA = HIGH;
breakB = HIGH;
speedA = 1;
speedB = 1;
}
if(command_value == 0) {
breakA = LOW;
breakB = LOW;
}
}
if(sval == "turn"){
if(command_value == 0){
speedB += turn_rate;
speedA -= turn_rate;
}
if(command_value == 255) {
speedB -= turn_rate;
speedA += turn_rate;
}
}
if(sval == "fspd") {
adjustSpeed();
dirA = fspd_direction;
dirB = fspd_direction;
speedA = go_speed;
speedB = go_speed;
//command_out = "fspd \t";
//command_out += String(go_speed);
//Serial.println(command_out);
//command_out = "";
}
if(sval == "fbtn") {
fspd_direction = LOW;
}
if(sval == "rbtn") {
fspd_direction = HIGH;
}
readString=""; // Clear readString
}
//**FILE4-OTHER STUFF**//
ReplyDeletevoid rgbShow () {
// for (long t = 0; t <= (periode*PI)/2; t++) {
time = millis();
value = 128+127*cos(2*PI/periode*time);
value2 = 128+127*cos(2*PI/periode*(displace-time));
value3 = 128+127*cos(2*PI/periode*(displace2-time));
rstate = value;
gstate = value2;
bstate = value3;
// }
}
// use these to report stuff back to serial
// nottice the command_out lines
void heyMan() {
if(report_motors) {
reportMotors();
}
}
void reportMotors() {
int sample_amount = 10;
for(int i = 0; i < sample_amount; i++) {
command_out = "cura";
command_out += String(motor_currency_a) + "\n";
command_out += "crrb";
command_out += String(motor_currency_b);
Serial.println(command_out);
}
command_out = "";
// Serial.println("currb \t"+motor_currency_b);
}
ReplyDelete**************
PROCESSING SKETCH!!
THIS IS NOT ARDUINO CODE (well not really)
http://processing.org/
*****************
import oscP5.*; // Load OSC P5 library
import netP5.*; // Load net P5 library
import processing.serial.*; // Load serial library
Serial arduinoPort; // Set arduinoPort as serial connection
OscP5 oscP5; // Set oscP5 as OSC connection
//String command = "";
String msg_out = "";
String prev_msg = "";
String incoming_command_value = "";
String incoming_prefix = "";
//String myOscAddr = "";
NetAddressList myNetAddressList = new NetAddressList();
/* listeningPort is the port the server is listening for incoming messages */
int myListeningPort = 8000;
/* the broadcast port is the port the clients should listen for incoming messages from the server*/
int myBroadcastPort = 8080;
String myConnectPattern = "/server/connect";
String myDisconnectPattern = "/server/disconnect";
String myAlertPattern = "/alert/";
void setup() {
size(325,500);
noStroke();
oscP5 = new OscP5(this, myListeningPort);
arduinoPort = new Serial(this, Serial.list()[0], 19200);
arduinoPort.bufferUntil('\n');
// frameRate(20);
}
private void connect(String theIPaddress) {
if (!myNetAddressList.contains(theIPaddress, myBroadcastPort)) {
myNetAddressList.add(new NetAddress(theIPaddress, myBroadcastPort));
println("### adding "+theIPaddress+" to the list.");
} else {
println("### "+theIPaddress+" is already connected.");
}
println("### currently there are "+myNetAddressList.list().size()+" remote locations connected.");
}
private void disconnect(String theIPaddress) {
if (myNetAddressList.contains(theIPaddress, myBroadcastPort)) {
myNetAddressList.remove(theIPaddress, myBroadcastPort);
println("### removing "+theIPaddress+" from the list.");
} else {
println("### "+theIPaddress+" is not connected.");
}
println("### currently there are "+myNetAddressList.list().size());
}
void draw() {
background(50);
}
void serialEvent (Serial Port) {
// get the ASCII string:
String inString = arduinoPort.readStringUntil('\n');
if (inString != null) {
// trim off any whitespace:
inString = trim(inString);
incoming_prefix = inString.substring(0, 5);
incoming_command_value = inString.substring(7, 9);
newOscMessage();
}
}
void newOscMessage() {
OscMessage myOscMessage = new OscMessage("/4/");
myOscMessage.setAddrPattern("/4/"+incoming_prefix);
myOscMessage.add(incoming_command_value);
oscP5.send(myOscMessage, myNetAddressList);
}
void oscEvent(OscMessage theOscMessage) {
if (theOscMessage.addrPattern().equals(myConnectPattern)) {
connect(theOscMessage.netAddress().address());
}
else if (theOscMessage.addrPattern().equals(myDisconnectPattern)) {
disconnect(theOscMessage.netAddress().address());
}
else if (theOscMessage.addrPattern().equals(myAlertPattern)) {
disconnect(theOscMessage.netAddress().address());
}
else {
try {
oscP5.send(theOscMessage, myNetAddressList);
} catch (Exception InvocationTarget) {}
finally {
String addr = theOscMessage.addrPattern();
String list[] = split(addr,'/');
String command = addr.substring(3,7);
float commandval = theOscMessage.get(0).floatValue();
int j = int(commandval*255);
String send_package = "<"+command +j +">";
msg_out = send_package;
}
try{
arduinoPort.write(msg_out);
} finally {
msg_out = "";
}
}
}
Thanks a lot Paul,
ReplyDeletedidnt expect such a fast reply :) and the full code! Great!
One question remains - i tried to get behind it, but maybe you can explain this math?
value = 128+127*cos(2*PI/oscPeriode*time);
so 128+127 i think is the the highest value (255) but why 128+ 127*cos
and why PI? I didnt solve it.... Maybe you can explain this?!
Thanks in advance!!
-andreas
ah yes... i renamed periode to oscPeriode as i also get this value out of OSC Input :) just to be clear i edited your function.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHey Paul,
ReplyDeleteits me again - is there a way to force the starting value at 254 or 0 ??
time = millis();
value = 128+127*cos(2*PI/oscPeriode*time);
redval = 255;
greenval = 0;
blueval = value;
It always starts at a different value rises up to 254 and fall down to 0 as expected...
Starting from 254 down to 0 or
starting from 0 and rise up to 254
is currently not under control by the beginning.
Anyway to get it?
Thanks a lot!
I think would need to setup another variable to capture the value of millis() when it starts and then subtract that from millis() in the loop.
ReplyDelete*and then another value if you wanted to start it at something other than 0
startvalue = 10 // this is the value you want to start at.
starttime = millis();
value = 128+127*cos(2*PI/oscPeriode*(time-starttime);
you might need to play around with where exactly you capture the starttime- depending on how your program is setup, you would want to do it right before you run the loop.
int startvalue = 175 // any number 0-255
ReplyDeletevoid loop() {
starttime = millis();
rgbshow(starttime)
}
void rgbshow(starttime) {
time = millis();
value = 128+127*cos(2*PI/oscPeriode*(time-(starttime+startvalue)));
}
******
I havent tested this but it seems legit
At first thanks for your great support and fast reply!!
ReplyDeleteI tried it in my current set up with no success - so i set up a new sketch with the following:
//initialize values
long time = 0;
long starttime = 0;
int startvalue = 5; // any number 0-255
int value = 0;
int oscPeriode = 5000;
void setup(){
//start serial output
Serial.begin(115200);
}
void loop() {
//set counter base
starttime = millis();
//run function
rgbshow(starttime);
}
void rgbshow(long starttime) {
//set function counter base
time = millis();
//generate value between 0-255 start with $startvalue
value = 128+127*cos(2*PI/oscPeriode*(time-(starttime+startvalue)));
//print generated value
Serial.println(value, DEC);
}
And the result is:
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
254
all the time. I tried to play with the position of the time values and the startvalue with no succes - changing startvaule change the result indeed but thats very clear with the math used.
I will try some changes - but maybe you have more success and you find the wrong part faster than me.
Honestly i still didnt get the idea behin cosinus and the PI maths in the value line :/ ...
Honestly I never quite understood the math myself (Only got as high as College Algebra II). I know it has to do with plotting a curve on a graph- might even be an EE formula for calculating frequencies?
ReplyDeleteI always intended to learn more about it since it seems understanding a function like this could be useful in a lot of ways. Just googling right now I came across this site, might give you some insight>
http://www.intmath.com/trigonometric-graphs/2-graphs-sine-cosine-period.php
Try this instead-
ReplyDeletevalue = 128+127*cos(2*PI/oscPeriode*time-(starttime+startvalue));
I think I left in an extra set of parenthesis in my previous reply...
My harddrive crashed over the weekend- so Im still trying to get everything set back up. Let me see if I can do this in Python to figure it out.
Hey Paul,
ReplyDeletemaybe it was my mistake put the starttime into the wrong place, but the first value math was okay so far.
Here is the result of my testing - it works for me so far with an arduino ethernet.
Thanks again for your support and i hope you have an backup of your harddrive!
/*
Fade !!ANALOG!! RGB LED-Strips without delay() for nonblocking program
rgbFadeAway fades blue->violet->red->yellow->green->teal->blue in loop
Thanks to Paul Kelly for the value math ->
http://electronomous.blogspot.de/2012/06/rgbshow-super-smooth-full-color-led.html
Further informationen of the math 2*PI....
http://www.intmath.com/trigonometric-graphs/2-graphs-sine-cosine-period.php
CC - andyw
nibelungen79[[at]]googlemail.com
*/
//init VALUES
//PIN config -change to your needs-
uint8_t redPin = 3;
uint8_t greenPin = 5;
uint8_t bluePin = 6;
//-nothing to change here-
uint8_t redval, greenval, blueval;
long time = 0;
long starttime = 0;
int startvalue = 255;
int value = 0;
int periode;
int cmode = 0;
void setup(){
//init LED STRIP -nothing to change here-
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
//setup void VALUES -change to your needs-
periode = 50000; //time in ms from 0-255 or 0-255
// change nothing below here
starttime = millis();
}
void loop(){
rgbFadeAway(starttime);
analogWrite(redPin, 255-redval);
analogWrite(greenPin, 255-greenval);
analogWrite(bluePin, 255-blueval);
}
void rgbFadeAway(long starttime) {
switch (cmode){
case 0:
time = millis();
value = 128+127*cos(2*PI/periode*(time-(starttime+startvalue)));
redval = 255-value;
greenval = 0;
blueval = 255;
if( value == 2){
cmode = 1;
}
break;
case 1:
time = millis();
value = 128+127*cos(2*PI/periode*(time-(starttime+startvalue)));
redval = 255;
greenval = 0;
blueval = 255-value;
if( value == 253){
cmode = 2;
}
break;
case 2:
time = millis();
value = 128+127*cos(2*PI/periode*(time-(starttime+startvalue)));
redval = 255;
greenval = 255-value;
blueval = 0;
if( value == 2){
cmode = 3;
}
break;
case 3:
time = millis();
value = 128+127*cos(2*PI/periode*(time-(starttime+startvalue)));
redval = 255-value;
greenval = 255;
blueval = 0;
if( value == 253){
cmode = 4;
}
break;
case 4:
time = millis();
value = 128+127*cos(2*PI/periode*(time-(starttime+startvalue)));
redval = 0;
greenval = 255;
blueval = 255-value;
if( value == 3){
cmode = 5;
}
break;
case 5:
time = millis();
value = 128+127*cos(2*PI/periode*(time-(starttime+startvalue)));
redval = 0;
greenval = 255-value;
blueval = 255;
if( value == 253){
cmode = 0;
}
break;
}
}
By the way - concerning the equation, it is the eqation used to calculate a sine wave:
ReplyDeletehttp://en.wikipedia.org/wiki/Sine_wave
So then were you able to control the starting value ok???
I was thinking it might be a little more complicated than I initially thought.
It seems like you would need to calculate a valid value differential from the time, because in fact there are an infinite number of possible values that would result in the wave coinciding with your desired output.
Also it seems like this value would change depending on the width (periode) of the wave...
Not sure but I definitely want to crack it.
In my sketch i use a webserver for user to change values in a led. When the LED is 255 and user change it to 100 or 200 , i would like to implement a smooth passage from one value to another. But without using the delay!...
ReplyDeletebasically i need a function that fade from given value1 to given value2 with an Artificial 1 second delay
Why do you introduce the variables displace and displace2?
ReplyDeleteFor technical or aesthetic reasons?
sorry its been quite awhile since i did this project. If memory serves me correctly the displace values simply serve to start the diff colors at different times so they dont fluctuate at the same time. I think there was a control to change these displace times.
ReplyDeleteso the initial color starts at 0 - the second uses displace and the third displace2
DeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... Cow Ghee
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... authentic italian recipes
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... bán chanh dây
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... giống chanh không hạt
ReplyDeleteStarting your baby on solids might seem challenging for moms, especially in large families. Here's good news: it does not have to be! Moms have been doing it for centuries without baby food in jars or other special baby items. This traditional and natural approach will not only save you money and effort, it will also guarantee and soft and healthy introduction of solid food into your baby's diet. Cultured ghee benefits
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... best cast iron skillet for outdoors
ReplyDeleteThe most ideal way to store vegetables and fruits at home, grocery stores or restaurants is to store them on a vegetable rack. It is a smart way to store vegetables in your kitchen; it gives you easy access to vegetables while cooking. Vegetables are the most natural from of food with each one of them being rich in one type of vitamin or the other. carote
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteLow maintenance gardens need not look like the bare type, not many plants, lots of rocks, paving, gravel etc. You can have a beautiful garden following a few principles. Choice of plants, type of plants, garden layout, mulching and a well thought out garden design. gilbert tree trimming
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... goodies online
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... https://golden-corral-complete-details-ultimate-guide-91.webselfsite.net/
ReplyDeleteI've been a raw foodist since January 2000, and have written five books around the subject. I also present a TV show all about raw food. You could say I'm passionate about it. But WHY? What can raw food do for you that cooked food can't? Well, how about this... cheap pineapple tart
ReplyDeleteAre you prepared for a food crisis? The western world takes for granted the food that we eat daily. We assume that since we have always had easy access to it, we always will. The truth is that our food supply is in a critical state and will eventually fail. Plan and prepare a food reserve to help you and your loved ones survive a food shortage or other disaster A2 Cow Ghee
ReplyDeleteDo you find yourself 'emotionally eating' most of the time? When was the last time you were at your goal weight/shape? Have you ever wondered how to overcome food cravings WITHOUT any willpower? Finally, a scientific approach has been proven. Food cravings are REAL but overcoming them can be EASY. You know you will want to read this because we want to share it with you. 토토먹튀사이트검증
ReplyDeleteYou have done a great job on this article. It’s very readable and highly intelligent. You have even managed to make it understandable and easy to read. You have some real writing talent. Thank you.출장안마
ReplyDeleteLow maintenance gardens need not look like the bare type, not many plants, lots of rocks, paving, gravel etc. You can have a beautiful garden following a few principles. Choice of plants, type of plants, garden layout, mulching and a well thought out garden design. Tree Removal Kelowna
ReplyDeleteTake a moment to imagine your garden. The birds are chirping, insects buzzing, the wind moving gently and gracefully through the plants and trees. What is missing in that picture? You sitting with the doors and windows open from your gorgeous garden cabin with a cool glass of iced tea, a book and a sense of utter contentment, of course! Garden cabins are the hottest home improvement and garden trend these days. Trust me, you need one. Tree Maintenance
ReplyDelete