Using a mapped value which is then ramped analog output

I am working on a project where I need to adjust a mapped value based on a switch position, but then I would like to ramp the the new analog data when I write it.

An example, lets say we want to make a button output different voltage (serial robot controller). From my knowledge it will look something like this:

 if( adjenpos == 1) {
boostbtnout = map(boostbtnin, 0, 1023, 0, 51);
}
else if( adjenpos == 2) {
boostbtnout = map(boostbtnin, 0, 1023, 0, 102);
}
else if( adjenpos == 3) {
boostbtnout = map(boostbtnin, 0, 1023, 0, 153);
}
else if( adjenpos == 4) {
boostbtnout = map(boostbtnin, 0, 1023, 0, 204);
}
else if( adjenpos == 5) {
boostbtnout = map(boostbtnin, 0, 1023, 0, 255);
}

Now with option 3, taking a button which has an on/off value of 0 or 153, I want to ramp the value 0 to 153 over a prescribed rate, instead of just on or off.

My assumption is to do something similar to this inside the loop:

boostramp = 1
boostbtnvalue = analogRead(boostbtnout)
 analogWrite(boostbtn, boostbtnvalue);
 if ( boostpwr <= boostbtnout){
 boostpwr = boostpwr + boostramp;

I know this is not correct, but how do I inject the new mapped values into a rampped type of function?

Thanks!

You're using a lot of words like "inject" and "ramp" which don't make a lot of sense, so let's try to be clear: the map function takes several arguments, does some math, and returns a value.

Second, you're saying you want to make a button output a voltage, which doesn't make sense either -- buttons are inputs.

So what I think you mean:
You want to make a project that reads a button and outputs a voltage if the button is pressed (if it's not pressed, output 0 volts). The voltage depends on how long the button has been pressed; increasing as it has been held longer.

If that's so, you'll want to make it so that when the button was not pressed last time but was pressed this time, it resets a clock (or sets a variable to now). Then you want to map the elapsed time (now - the stored time) into a voltage that you feed to analogWrite.

now can be figured out using the millis() command. You can use a variable declared as static to keep a variable (such as the time when the button was first pressed) between iterations of a loop. The rest I think you know how to do.

Hi squd08,

It's hard to tell what you are trying to do from the code snippets you've included. You really should comment your code and explain what the variables mean.

May I suggest you replace the cascading if, else-if statements with a simple switch statement?

switch (adjenpos)
{
    case 1:  boostbtnout = map(boostbtnin, 0, 1023, 0, 51);  break;
    case 2:  boostbtnout = map(boostbtnin, 0, 1023, 0, 102);  break;
    Etc...
}

Or, even simpler, create an array of upper values that you index with adjenpos?

int switch_pos []= {51, 102, etc...};

...

boostbtnout = map(boostbtnin, 0, 1023, 0, switch_pos[adjenpos]);

// pardon my code if it doesn't compile, it's late for me and I'm a bit groggy :-/

I assume that what you are really wanting is a smooth transition between the current value and the new value based on switch position. You should store the current value in a variable and loop to the desired value (which may be up or down from it!). Use delays to ensure the transition is according to your 'prescribed' rate.

WizenedEE:
You're using a lot of words like "inject" and "ramp" which don't make a lot of sense, so let's try to be clear: the map function takes several arguments, does some math, and returns a value.

Second, you're saying you want to make a button output a voltage, which doesn't make sense either -- buttons are inputs.

So what I think you mean:
You want to make a project that reads a button and outputs a voltage if the button is pressed (if it's not pressed, output 0 volts). The voltage depends on how long the button has been pressed; increasing as it has been held longer.

If that's so, you'll want to make it so that when the button was not pressed last time but was pressed this time, it resets a clock (or sets a variable to now). Then you want to map the elapsed time (now - the stored time) into a voltage that you feed to analogWrite.

now can be figured out using the millis() command. You can use a variable declared as static to keep a variable (such as the time when the button was first pressed) between iterations of a loop. The rest I think you know how to do.

Sorry, it's hard to type as it makes sense in my head XD
Ultimately I am sending signals to a robot controller and using a on/off switch to control a motor. I am using the adjustable map values to vary my maximum power and the "ramp" to have a smooth motor application. I know it sounds like a complicated effort, but its all for good reason.

so to sum up,
I want to make a project which reads a button digitally, and outputs a "progressive" voltage.
In order to output to analog we have to map it, so a button LOW = 0 HIGH = 255 (or whatever number I choose)
But instead of it being just 0 or 255, I would like it to climb from 0 to 255 over a set period of time or loops. You could call it ramp, fade, etc.

Is this any clearer? Sorry for the confusion.

patduino:
Hi squd08,

It's hard to tell what you are trying to do from the code snippets you've included. You really should comment your code and explain what the variables mean.

May I suggest you replace the cascading if, else-if statements with a simple switch statement?

switch (adjenpos)

{
   case 1:  boostbtnout = map(boostbtnin, 0, 1023, 0, 51);  break;
   case 2:  boostbtnout = map(boostbtnin, 0, 1023, 0, 102);  break;
   Etc...
}




Or, even simpler, create an array of upper values that you index with adjenpos?



int switch_pos []= {51, 102, etc...};

...

boostbtnout = map(boostbtnin, 0, 1023, 0, switch_pos[adjenpos]);




// pardon my code if it doesn't compile, it's late for me and I'm a bit groggy :-/

I assume that what you are really wanting is a smooth transition between the current value and the new value based on switch position. You should store the current value in a variable and loop to the desired value (which may be up or down from it!). Use delays to ensure the transition is according to your 'prescribed' rate.

Thanks Pat! I hope my last comment helps clear up any confusion.

I am a basic arduino user, but I like your suggestions on the if statements. I will revisit when I have a direction for my main issue. I appreciate it!

Yes, things are getting clearer for me.

When you say you want to adjust the voltage to the motor, you really mean that you want to adjust the PWM values, right? You can't actually change the voltage levels out of the Arduino.

Are you controlling 1 motor or several? If several, are you controlling one at a time, or do you want the motors to ramp to their new speeds at the same time?

squid08:

WizenedEE:
You're using a lot of words like "inject" and "ramp" which don't make a lot of sense, so let's try to be clear: the map function takes several arguments, does some math, and returns a value.

Second, you're saying you want to make a button output a voltage, which doesn't make sense either -- buttons are inputs.

So what I think you mean:
You want to make a project that reads a button and outputs a voltage if the button is pressed (if it's not pressed, output 0 volts). The voltage depends on how long the button has been pressed; increasing as it has been held longer.

If that's so, you'll want to make it so that when the button was not pressed last time but was pressed this time, it resets a clock (or sets a variable to now). Then you want to map the elapsed time (now - the stored time) into a voltage that you feed to analogWrite.

now can be figured out using the millis() command. You can use a variable declared as static to keep a variable (such as the time when the button was first pressed) between iterations of a loop. The rest I think you know how to do.

Sorry, it's hard to type as it makes sense in my head XD
Ultimately I am sending signals to a robot controller and using a on/off switch to control a motor. I am using the adjustable map values to vary my maximum power and the "ramp" to have a smooth motor application. I know it sounds like a complicated effort, but its all for good reason.

so to sum up,
I want to make a project which reads a button digitally, and outputs a "progressive" voltage.
In order to output to analog we have to map it, so a button LOW = 0 HIGH = 255 (or whatever number I choose)
But instead of it being just 0 or 255, I would like it to climb from 0 to 255 over a set period of time or loops. You could call it ramp, fade, etc.

Is this any clearer? Sorry for the confusion.

That's about what I guessed. Try implementing what I described in the last two paragraphs of my post and come back with questions about how to do so

I have just learned that I can send a serial command to the robot controller to adjust the top power limit on the robot controller. This something which I did not think was possible without a reset.

That being said, the process is still the same, but I can essentially remove the "IF map statements

patduino:
Yes, things are getting clearer for me.

When you say you want to adjust the voltage to the motor, you really mean that you want to adjust the PWM values, right? You can't actually change the voltage levels out of the Arduino.

Are you controlling 1 motor or several? If several, are you controlling one at a time, or do you want the motors to ramp to their new speeds at the same time?

Yes, adjust pwm. So instead of a pwm output of 0 or 255, its 0 to 255 over a set period of time. Just one motor.

Thanks!

WizenedEE:

squid08:

WizenedEE:
You're using a lot of words like "inject" and "ramp" which don't make a lot of sense, so let's try to be clear: the map function takes several arguments, does some math, and returns a value.

Second, you're saying you want to make a button output a voltage, which doesn't make sense either -- buttons are inputs.

So what I think you mean:
You want to make a project that reads a button and outputs a voltage if the button is pressed (if it's not pressed, output 0 volts). The voltage depends on how long the button has been pressed; increasing as it has been held longer.

If that's so, you'll want to make it so that when the button was not pressed last time but was pressed this time, it resets a clock (or sets a variable to now). Then you want to map the elapsed time (now - the stored time) into a voltage that you feed to analogWrite.

now can be figured out using the millis() command. You can use a variable declared as static to keep a variable (such as the time when the button was first pressed) between iterations of a loop. The rest I think you know how to do.

Sorry, it's hard to type as it makes sense in my head XD
Ultimately I am sending signals to a robot controller and using a on/off switch to control a motor. I am using the adjustable map values to vary my maximum power and the "ramp" to have a smooth motor application. I know it sounds like a complicated effort, but its all for good reason.

so to sum up,
I want to make a project which reads a button digitally, and outputs a "progressive" voltage.
In order to output to analog we have to map it, so a button LOW = 0 HIGH = 255 (or whatever number I choose)
But instead of it being just 0 or 255, I would like it to climb from 0 to 255 over a set period of time or loops. You could call it ramp, fade, etc.

Is this any clearer? Sorry for the confusion.

That's about what I guessed. Try implementing what I described in the last two paragraphs of my post and come back with questions about how to do so

Yes your right. I realize now this morning that your approach is applicable. Is it more efficient to do it with a for loop count since we are talking about a 0.1 to 1 second "ramp" , or is still best to do as you suggest and use the internal clock?

WizenedEE:
That's about what I guessed. Try implementing what I described in the last two paragraphs of my post and come back with questions about how to do so

This is my first attempt at the code.
How does it look?

void loop () {

if (button == HIGH && time <= millis() ){

int time = millis();

}

else if (button == HIGH && time > millis() ){

int buttontime = millis()-time;

ramp = map(buttontime, time, 1000, 0, 255);  // after 1 second give full pwm output

}

else if (button == LOW) {

time = 0;

}

squid08:
How does it look?

Not indented.

Arrch:

squid08:
How does it look?

Not indented.

?

squid08:

WizenedEE:
That's about what I guessed. Try implementing what I described in the last two paragraphs of my post and come back with questions about how to do so

This is my first attempt at the code.
How does it look?

That looks really good! Just a few tips and it should work great. I modified it a little

void loop () {
  static unsigned long startButtonPressTime;
  static byte lastButtonState = LOW;
  int pwr;
  byte buttonState = digitalRead(button);

  if (buttonState == HIGH) {
    if (lastButtonState = LOW) {
      startButtonPressTime = millis();
    }
    else {
      pwr = map(millis() - startButtonPressTime, 0, 1000, 0, 255);  // after 1 second give full pwm output
    }
  }
  analogWrite(3, pwr);

  lastButtonState = buttonState;
}

squid08:

Arrch:

squid08:
How does it look?

Not indented.

?

'Indenting' refers to laying out your code so that the structure can be seen and understood. It doesn't affect the logic, but does affect how easy it is for the programmer to understand the logic. The code you posted wasn't indented and as a result is very hard to follow. The Arduino IDE includes tools to indent your code for you.

WizenedEE:

squid08:

WizenedEE:
That's about what I guessed. Try implementing what I described in the last two paragraphs of my post and come back with questions about how to do so

This is my first attempt at the code.
How does it look?

That looks really good! Just a few tips and it should work great. I modified it a little

void loop () {

static unsigned long startButtonPressTime;
  static byte lastButtonState = LOW;
  int pwr;
  byte buttonState = digitalRead(button);

if (buttonState == HIGH) {
    if (lastButtonState = LOW) {
      startButtonPressTime = millis();
    }
    else {
      pwr = map(millis() - startButtonPressTime, 0, 1000, 0, 255);  // after 1 second give full pwm output
    }
  }
  analogWrite(3, pwr);

lastButtonState = buttonState;
}

Thanks! I'm happy to have solved it mostly myself.

Can you explain the purpose of byte and unsigned long?

squid08:
Thanks! I'm happy to have solved it mostly myself.

Can you explain the purpose of byte and unsigned long?

They're other types of integers. in an arduino (it changes), an int is two bytes; a byte is one byte; and a long is four bytes. `unsigned' means it will never be negative, so instead of representing (for a 1 byte number for example) -128 to 127, an unsigned byte can represent 0 to 255.

unsigned long is the type returned by millis() so it should be used for variables storing the time.
byte is the shortest possible value so I used it to save memory because it can only be HIGH or LOW anyway

WizenedEE:

squid08:
Thanks! I'm happy to have solved it mostly myself.

Can you explain the purpose of byte and unsigned long?

They're other types of integers. in an arduino (it changes), an int is two bytes; a byte is one byte; and a long is four bytes. `unsigned' means it will never be negative, so instead of representing (for a 1 byte number for example) -128 to 127, an unsigned byte can represent 0 to 255.

unsigned long is the type returned by millis() so it should be used for variables storing the time.
byte is the shortest possible value so I used it to save memory because it can only be HIGH or LOW anyway

Your description makes sense. Thanks.

Now, I was trying to understand how to simplify my "if else if" statements into an array as previously advised. I will have multiple switches with plenty of options for each, and for the sake of code speed, I will need to minimize what happens in each loop.

Can you help me make sense of how to apply the array to an output with multiple possibilities? Also, the idea of having the arduino check if the switch has moved and if it hasn't avoiding that part of the loop in entirety.

I have tried to search beyond the basic description of array, but I can't find the proper wording.