Sometimes we need to take a series of values from a device connected to an analog input, modify those values and output them in a different fashion. One common example of this is reading a potentiometer and using that to position a servo. However, the series of values from the potentiometer will range from 0 to 255, while the servo output through servopos needs to range from 75 to 225. We need to transform the input data to meet output requirements. In this particular case the transformation is simple one. We need to change the slope and adjust the ‘y-intercept’ or, perform a translation. This is what is called an affine transformation.
Generally speaking for an affine transform of this nature, given a variable X, which has range between XL and XH that we wish to transform to another variable, Y, with a range given by YL to YH we must us the following formula:
Y=(YH-YL)/(XH-XL)*(X-XL)+YL (1)
Now, let’s say we have a PICAXE-08M2 with the wiper of a potentiometer attached to C.1 and a servo attached to C.4. We intend to read the value of the potentiometer into variable b0. Transform the data as required and put the result into b1. We will then use b1 to position the servo.
In our case, X is the variable b0, read from the ADC using the command readadc C.1, b9 and whose range is 0 to 255, and Y is the variable b1 whose range we shall call b1L to b1H, so we can simplify (1) to our 'general case' of:
b1=((b1H-b1L)/255)*b0+b1L (2)
Now, apply this to our scenario where we wish to control a servo, the range we need is b1L=75 and b1H=225. Plugging in these values to (2) we get:
b1=((225-75)/255)*b0+75 (3)
Given the limitation of the integer math and the order of operations imposed by PICAXE basic, we must rearrange (3) to become:
b1=150*b0/255+75 (4)
Which will provide the results we require to use a pot to control a servo.
Now for a little more theory. We can now formulate 2 general affine transformations that can be used in PICAXE basic. The first uses a fixed range that we calculate before hand and hard code into the program. This formula would be useful in a case like the one that started this thread. Given an spread of R=b0H-b0L in the range of b0, and a desired output range of b1L to b1H we have:
b1=[b1H-b1L]*b0/R+b1L, (5)
Where the term [b1H-b1L] is pre-calculated as an integer and coded into the program like we have already shown in (4). In that case R=255.
The second uses a programmable range determined at run-time. This would be useful in cases where the transformation would need to be adapted to changing conditions or to various output devices. Given a spread of the range of b0 (R from above) in b4, and a desired output range in variables b2 and b3 where b2 < b3, we have:
b1=b3-b2*b0/b4+b2 (6)
Code Example 1 - As in our text, to control a servo with a full-range potentiometer and using equation (5), where:
b1L = 75
b1H = 225
R=255
Code example 2 – Using the more general form, again control a servo that needs only a limited motion to vary a control valve based on a potentiometer that tells us a float level in a liquid tank. The potentiometer readings vary between 0 and 150 and the servo must be positioned between 100 and 180. Then using equation (6) we have:
Generally speaking for an affine transform of this nature, given a variable X, which has range between XL and XH that we wish to transform to another variable, Y, with a range given by YL to YH we must us the following formula:
Y=(YH-YL)/(XH-XL)*(X-XL)+YL (1)
Now, let’s say we have a PICAXE-08M2 with the wiper of a potentiometer attached to C.1 and a servo attached to C.4. We intend to read the value of the potentiometer into variable b0. Transform the data as required and put the result into b1. We will then use b1 to position the servo.
In our case, X is the variable b0, read from the ADC using the command readadc C.1, b9 and whose range is 0 to 255, and Y is the variable b1 whose range we shall call b1L to b1H, so we can simplify (1) to our 'general case' of:
b1=((b1H-b1L)/255)*b0+b1L (2)
Now, apply this to our scenario where we wish to control a servo, the range we need is b1L=75 and b1H=225. Plugging in these values to (2) we get:
b1=((225-75)/255)*b0+75 (3)
Given the limitation of the integer math and the order of operations imposed by PICAXE basic, we must rearrange (3) to become:
b1=150*b0/255+75 (4)
Which will provide the results we require to use a pot to control a servo.
Now for a little more theory. We can now formulate 2 general affine transformations that can be used in PICAXE basic. The first uses a fixed range that we calculate before hand and hard code into the program. This formula would be useful in a case like the one that started this thread. Given an spread of R=b0H-b0L in the range of b0, and a desired output range of b1L to b1H we have:
b1=[b1H-b1L]*b0/R+b1L, (5)
Where the term [b1H-b1L] is pre-calculated as an integer and coded into the program like we have already shown in (4). In that case R=255.
The second uses a programmable range determined at run-time. This would be useful in cases where the transformation would need to be adapted to changing conditions or to various output devices. Given a spread of the range of b0 (R from above) in b4, and a desired output range in variables b2 and b3 where b2 < b3, we have:
b1=b3-b2*b0/b4+b2 (6)
Code Example 1 - As in our text, to control a servo with a full-range potentiometer and using equation (5), where:
b1L = 75
b1H = 225
R=255
Code:
servo C.4,150
do
readadc C.1,b0
b1=150*b0/255+75
servopos C.4,b1
loop
Code example 2 – Using the more general form, again control a servo that needs only a limited motion to vary a control valve based on a potentiometer that tells us a float level in a liquid tank. The potentiometer readings vary between 0 and 150 and the servo must be positioned between 100 and 180. Then using equation (6) we have:
Code:
let b3 = 180
let b2 = 100
let b4 = 150
servo C.4,100
do
readadc C.1,b0
b1=b3-b2*b0/b4+b2
servopos C.4,b1
loop