Go Down

Topic: Using a mapped value which is then ramped analog output (Read 1 time) previous topic - next topic

squid08

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:

Code: [Select]
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:

Code: [Select]
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!

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.

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?  

Code: [Select]
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?

Code: [Select]
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.
There are 10 types of people in the world, those that understand binary, and those that don't.

squid08


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.



squid08


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?  

Code: [Select]
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?

Code: [Select]
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!

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?
There are 10 types of people in the world, those that understand binary, and those that don't.

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

squid08


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


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!

squid08




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? 

squid08



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?

Code: [Select]
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;

}

Arrch



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
Code: [Select]

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;
}

PeterH




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.
I only provide help via the forum - please do not contact me for private consultancy.

squid08





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
Code: [Select]

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?

Go Up