Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   Need help with PWM 1-2ms pulse control (http://www.chiefdelphi.com/forums/showthread.php?t=67397)

Generalx5 01-05-2008 00:34

Re: Need help with PWM 1-2ms pulse control
 
Alright...I've resoldered the pot now, and its working nicely.

....now into the problem with the casting Set A and Set B. Im not sure what you mean by casting 0 - 126 to Set A and casting 127 - 254 to Set B.

Do you mean that When the switch is set to A side, it will only activate PWM pulses between 0 - 126? and the same with side B ( 127-254)?

How should I seperate the pulses into two groups? Ive only been able to get 1 side of it working. I doubled the numerical value of the pot and that gave me the ability to control PWM pulses between 0 - 127. So it would look something like this:

Before pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 254 / 1024;

After pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 254 / 2048;

Im stumped. Sorry for all these questions, Im not a programmer, but I need to figure this out, so any help is much appreciated.

yongkimleng 01-05-2008 02:24

Re: Need help with PWM 1-2ms pulse control
 
on the software side, heres my take.

I read that you want to map the analog pot directly to the pwm out right, so heres what I'd do:

pwm01 = Get_Analog_Value(rc_ana_in01) >> 2;

Now for the question on having two "sets".

Assuming you are getting full 10 bits range now and you want two sets
char set = 1; // set to 0 for the other set, or hook a switch up to this variable.

if(set == 1) {
// 127 to 254
pwm01 = (Get_Analog_Value(rc_ana_in01) >> 3) + 127;
} else {
// 127 to 0
pwm01 = 127 - (Get_Analog_Value(rc_ana_in01) >> 3);
}

maybe you need to add some casting above but on overall it should be correct.

Explanation:
Get_Analog_Value(rc_ana_in01) >> 3

Previously it was '>> 2', because I'm doing a bit shift so that the range from 0-1023 becomes 0-254 (8bits)

Now its >>3 as I'm sizing the range to 0-127 (7 bits) to be used in the calculation to scale set 1 (127 to 254) or set 2 (127 to 0).

Mark McLeod 01-05-2008 09:10

Re: Need help with PWM 1-2ms pulse control
 
Quote:

Originally Posted by Generalx5 (Post 744662)
....now into the problem with the casting Set A and Set B. Im not sure what you mean by casting 0 - 126 to Set A and casting 127 - 254 to Set B.

Do you mean that When the switch is set to A side, it will only activate PWM pulses between 0 - 126? and the same with side B ( 127-254)?

How should I seperate the pulses into two groups? Ive only been able to get 1 side of it working. I doubled the numerical value of the pot and that gave me the ability to control PWM pulses between 0 - 127. So it would look something like this:

Before pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 254 / 1024;

After pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 254 / 2048;

I think you're a programmer now :) and an electrician, you're just learning more stuff.

James' suggestions get into some interesting low-level programming tricks that you probably want to bypass for now.
The same with the other math shortcuts suggested. Understand how you map from one range to another then you can play with shortcuts. (Nobody likes long division...)

You already mapped one range into another when you took the analog 0-1023 and mapped it into the range 0-254.
It's the same for going to the range 0-127 or 127-254 or any other range of data.

It's just a ratio: analog input / analog full range = pwm output / pwm full range
or
input/1024 = pwm01 / 254

With a little math manipulation that ratio can be expressed as:
pwm01 = (analog input) * 254 / 1024
where the 254 is your full pwm range (the range you want to end up at) and 1024 is the full analog input range (the range you start with).
That's why replacing 1024 with 22 worked for you earlier. Your full range then was just 22.

Instead of your answer:
After pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 254 / 2048;

Keep the ranges you are working with (starting with a range of 1024 and ending up with a range of 127) and you'll get a more understandable result:
After pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 127 / 1024;

----------------
Here's the curve ball:
All that works fine for ranges starting at zero, and it's not too hard to work the math around to a range of 127-254 by just adding 127. There is an additional robotics trick here though that throws a wrench into this second range, because 127, in the middle, is neutral.

You should think about how you want your servo to behave when you switch between the two Sets. By just shifting the range up by adding 127 your servo will be at rest when the pot is all the way up, but at full speed when you throw the switch.
You might want to think about having the pot be the same for both sets when it's in one position. That just means inverting the second Set range and making it 254-127 instead. Mapping an analog input of 0 to be 127 for both Sets will have your servo stopped for both Sets when the pot is all the way down, and at full speed in both when it's all the way up.

Care to take a guess on how to invert the range 127-254 to make it 254-127 instead?
You could instead invert 0-127 to make it 127-0 if that's easier to think about. Then add 127 to that.

-------------------------------------
Switches:
Using the default EDU code the first two ports (1 & 2) are analog inputs, the others are mixed digital INPUTS (6,8,10,12,14,16) or OUTPUTS (all the others). You can change these if you want where you saw the TWO_ANALOG setup before.
Make sure you use an INPUT and just hook a switch between the signal and ground (DO NOT use the center +5v power pin).
It'll appear in the code with a value of 0 or 1 and the code to check it looks like:
Code:

pwm01 = (long) Get_Analog_Value(rc_ana_in01) * 127 / 1024;  // It's going to end up in a range of 127 for either Set A or B
 
if (rc_dig_in06 == 1)
{
    // Invert the value of pwm01 and move the range to 254-127
}
else
{
    // Leave the range as it is
}


Generalx5 01-05-2008 14:13

Re: Need help with PWM 1-2ms pulse control
 
Haha, wow! You make it sound so simple. Heres my attempt....

I've been able to keep set B as Pwm=127 when pot is close to 0, and Pwm=255 when pot is close to 1023.

As for set A, I did the plus 127 method. Pwm= ((analog signal) * -127 / 1023) + 127

so that gets me close to Pwm= 0 when the pot goes to 1023.
close to Pwm=127 when pot goes to 0.


This way, I've made the ratio a negative number, when I enter 1023 for the analog signal, the pwm will result in -127, so by adding 127 at the end, I will obtain 0 when the Pot is at 1023 or close to it. When the pot is close to 0, 0*(-127/1023) = -127 + 127, I get a 0 for the PWM.

So this actually works out to this situation:

Pot @ 1024 SetA Pwm= 0 SetB Pwm= 255
Pot @ 0 SetA Pwm=127 SetB Pwm=127

Il have to play with the numbers some more to give it a neutral band in the middle. This is all theory, but I've havnt tested it on my mini rc yet, so when I get back, ill' give it a try.

Generalx5 01-05-2008 16:52

Re: Need help with PWM 1-2ms pulse control
 
if (rc_dig_in06 == 1)
{
pwm01 = ((long) Get_Analog_Value(rc_ana_in01) * (127 / 1023) + 127);
}
if (rc_dig_in06 == 0)
{
pwm01 = ((long) Get_Analog_Value(rc_ana_in01) * (- 127 / 1023) + 127);
}

Tada! I think this is right, ill have to give it a try when I get home...

Alan Anderson 01-05-2008 18:39

Re: Need help with PWM 1-2ms pulse control
 
When you have two mutually exclusive tests like that, you can use the if statement's else clause.

Code:

if  (rc_dig_in06 == 1)
{
        pwm01 = (long) Get_Analog_Value(rc_ana_in01) *  127 / 1023 + 127;
}
else
{
        pwm01 = (long) Get_Analog_Value(rc_ana_in01) * -127 / 1023 + 127;
}

Note that I've removed the parentheses around (127/1023). With them in place, the intermediate result of the division will be zero, and I believe you'll find the output never varies from 127. Instead, you want to defer the division until as late as possible so you don't lose bits that you need.



I'd actually have done it a little differently:
Code:

pwm01 = (int)127 + Get_Analog_Value(rc_ana_in01) * rc_dig_in06?127:-127 / 1023;
But that's probably more cryptic than it needs to be for your purposes.

yongkimleng 02-05-2008 00:10

Re: Need help with PWM 1-2ms pulse control
 
If you're driving a victor from this, I don't think you need to worry about deadband. The victor has quite abit of deadband around the 127 region.

As for a servo.. well it may jitter around (not so sure).

You may want to print out the values to screen to see how much its jittering at. Maybe add a small (0.1uf? 1nF?) capacitor from signal to ground for the analog input. That usually helps when my analog cable is non-shielded and very long...

Edit:
apologies for using bit shifting, so I shall add a bit to explain what it is

>> is essentially known as 'bit shifting'.

Skipping the complicated details, it is simply:
a >> 1 same as a / 2
a >> 2 same as a / 4
a >> 3 same as a / 8
a >> 4 same as a / 16
The difference is that a bit shift operation takes significantly lesser processing time compared to a divide (unless compiler optimized).

Similarly, a << 1 same as a * 2
a << 2 same as a * 4
and so on.

Generalx5 02-05-2008 15:50

Re: Need help with PWM 1-2ms pulse control
 
Thanks everyone! It works perfectly. Now im able to do exactly what I wanted =D. This might be a bit hard on the servo but I think it shouldnt be too bad. Im testing this on a small scale robot, just trying to come up with driving abilities...where at a flick of a switch, the robot can start driving backwards, essentially turning the rear end of the robot into the front. I think this helps the drivers a little since they dont move their joysticks in reverse.

Generalx5 02-05-2008 18:46

Re: Need help with PWM 1-2ms pulse control
 
Is it possible to define a fuction?

#define let_go pwm01 = ((long) Get_Analog_Value(rc_ana_in01) * (- 127 / 1023) + 127)

I need to set up an array of these functions, possibly even make it so that a bunch of pwms = to that function.

Generalx5 02-05-2008 19:27

Re: Need help with PWM 1-2ms pulse control
 
Oh wow!

Sorry guys, I've somewhat impatient, I've took the time to test this code with a #define.

#define Let_go P1 = ((long) Get_Analog_Value(rc_ana_in01) * ( 127 / 1023) + 127)

in this case, I defined Let_go to represent the P1 which is the pwm01. And everytime Let_go is called upon, the pwm output would correspond to the potentiometer that i am adjusting. Hahah this is so cool to see programming language turning into physical movement. Wonderful...

Generalx5 03-05-2008 02:16

Re: Need help with PWM 1-2ms pulse control
 
In the code, in the User_routine file, there is a fuction called Limit_Switch_Max && Limit_Switch_Min && Limit_Mix.

Do I need those? What is the purpose for that to be there? It appears to be some sort of drive system limiter. But is it okay it I delete that? Im using something else instead.


Are the interrupts better digital inputs than making more digital inputs from the 1-16 pins? Im just courious as to if maybe the interrupts may have an advantage over the others since by default the are digital inputs.

Mark McLeod 03-05-2008 07:58

Re: Need help with PWM 1-2ms pulse control
 
Quote:

Originally Posted by Generalx5 (Post 745312)
In the code, in the User_routine file, there is a fuction called Limit_Switch_Max && Limit_Switch_Min && Limit_Mix.

Do I need those? What is the purpose for that to be there? It appears to be some sort of drive system limiter. But is it okay it I delete that? Im using something else instead.


Are the interrupts better digital inputs than making more digital inputs from the 1-16 pins? Im just courious as to if maybe the interrupts may have an advantage over the others since by default the are digital inputs.

You don't need those functions in user_routines.c, so they can be deleted.
The Limit_Switch_Min/Max are examples of how functions work, while Limit_Mix is handy for making a joystick behave arcade-style.

For what you're doing the interrupt digital inputs will behave just like the other digital inputs, so you can simply use them.
The interrupt inputs have some special properties that make them useful in very time critical tasks. Measuring and reacting to things much faster than a hand operated switch. We take advantage of interrupts with special sensors or highly accurate timed events.

------------------
I'd take the parentheses away from your real code as Alan suggested in his previous post, or move them.
In the integer math you're doing it's important to do all your multiplications first followed by any divisions.
Code:

analog input * 127 / 1023  or (analog input * 127) / 1023
// rather than
analog input * ( 127 / 1023)

This starts getting into more quirks of programming, but because of the integer data types we're using, each step in the calculation only allows a whole integer result.

So if analog input = 512 (halfway on the pot)
analog input * (127 / 1023) would be calculated by the EDU as 512 * (0) because 127/1023=0.0254154 which gets truncated to the integer 0

If the parenthesis are removed (or moved) then
(analog input * 127) / 1023 = (512 * 127) / 1023 = 8704 / 1023 = 85.33333 = 85

So the order you do calculations becomes very important.

Generalx5 06-05-2008 00:08

Re: Need help with PWM 1-2ms pulse control
 
Great! I totally forgot about that, I just put those brackets on just in case I get errors, I've seen at least 100 syntax error messages in about 2 real hours spent on programming. =D But I am contempt with my code as of now, it works the way I thought it would have.

Thanks for all the great support! Especially Mr. McLeod! Thank you so much!


All times are GMT -5. The time now is 08:54.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi