Designing a simple "RC" controller - Page 1
Forum section: electronics / beginners

author: joker1283
author_rank: Newbie
timestamp: November 25, 2017, 11:23:09 pm
content: When I used to fly RC helicopter, I can adjust a "curve" on my radio transmitter that relates the motion of the control stick (transmitter) to the motion of the servo at the receiving end. This curve was displayed on a screen and allows user to tune the sensitivity of servo movement at various points. For example, for lower sensitivity, one would have to move the control stick quite a bit for only a little bit of servo movement. This is useful for tasks like hovering where you don't want to overcompensate. For acrobatics, the reverse is true, you want quick response to any input at the control stick.I want to design a similar device using a microcontroller (like Arduino), a LCD screen, and a motor (either stepper or servo) for output (analogous to the servo on the RC heli), and some kind of input (analogous to the control stick on the transmitter). For the input, the user shall move a linear rack and pinion system, with the pinion hooked to a rotary encoder.Ideally, the user can push the rack back and forth, which controls the corresponding linear movement at the output. The user should be able to adjust the movement curve on the screen. Furthermore, there should be multiple curves (or mode) that the user can switch back and forth. Any mode switch would be done only when the servo and the rack are at their initial position (or when the system is in a "mode change" mode).The input and output are at the same device so we don't have to worry about wireless transmission of signals like that of a real RC application.Can someone give me a rough overview of what I need and how this can be implemented?Thanks

author: Nitrousoxide
author_rank: Regular Contributor
timestamp: November 26, 2017, 01:52:59 pm
content: What are the user requirements? You've stated roughly what it needs to do, but not any specific needs. (i.e. 5 hour battery life)Whats the end goal, to produce a PCB or is it just going to be hacked together protoboards?There are plenty of ways to tackle something like this. If it were me, I'd probably address it in sections:- Power supply: Battery charging, DC-DC- Processing: Any microcontroller, MSP432.- Motor Driver: Depends on load.- Display: Some generic SPI display(?)Analog inputs would require appropriate filtering and protection.Regardless of hardware requirements, it sounds like this is more of a software question that you're posing.In this case, you can use something known as a "Look up Table", also known as a LUT. Look up tables allow you to map a linear input to a non-linear output, this method is used in a lot of applications (one example is LED brightness curves).You can implement a LUT through the use of a precomputed array to save on processing time.Again, not too sure what you are driving with the resulting signal and you may require a closed loop feedback system after the LUT.

author: Frankie1AbC
author_rank: Newbie
timestamp: November 26, 2017, 06:49:38 pm
content: Maybe you should check out Arduino Mini and NRF24L01 modules

author: joker1283
author_rank: Newbie
timestamp: November 29, 2017, 07:49:02 pm
content: Quote from: Nitrousoxide on November 26, 2017, 01:52:59 pmHi, thanks for the reply.For the output, I plan to use a stepper motor, like the 28byj-48 motor. Power supply will be 4 NiMh AA batteries in series, and this will be used to power everything, including the motor, the microcontroller, etc.I don't really have requirements on battery life. I'm sure the 4 AA batteries would last more than enough.The end goal is to make a PCB, but for now, I'm going to try to use a breadboard first to make sure whatever design I use works. Size is not critical at this time.I also don't plan to use any feedback mechanism. Positional accuracy is not critical.The part that I need advice on is how to implement that "curve" and displaying it on a screen. You mentioned lookup table. As I understand, the lookup table stores the position information between the input and output correct? How do I actually code this up (I guess this is more of a software question) if I used a stepper motor without feedback? I believe one can only tell the stepper how many "steps" to take and at what speed. So maybe I need to take the derivative of the positions in the lookup table and use that as the stepping frequency?thanks

author: laneboysrc
author_rank: Contributor
timestamp: November 30, 2017, 06:08:16 am
content: There are open source RC transmitter projects that you may be able to use as starting point:http://www.deviationtx.com/http://www.open-tx.org/to name a few. They are not based on Arduino, but the calculations are just math anyway.The code you are looking for is usually part of the "mixer" functionality.hope it helps, Werner

author: xani
author_rank: Frequent Contributor
timestamp: November 30, 2017, 07:52:17 am
content: As for curve, you generally have 2 approachesOne is to make an array that acts as lookup table between input and output value + give user way to tune that (say few pre-generated curves + ability to edit them like change slope/gain)Advantage is that you can do anything and it is fast (just a memory lookup per event), disadvantage is RAM usageOther is just to make it one of predefined, parametrized functions (conversely same functions can be used to generate lookup table in the first method) and just give user access to those parametersAs for driving the stepper, I'd just use resulting value as "steps per second" and feed it to loop responsible for driving the stepper motor.

author: Nitrousoxide
author_rank: Regular Contributor
timestamp: November 30, 2017, 10:12:39 am
content: Quote from: joker1283 on November 29, 2017, 07:49:02 pmCool, make sure you implement some form of protection and charge control. Inevitably you'd need to use some form of regulator, either linear or switching (dc-dc buck).Quote from: joker1283 on November 29, 2017, 07:49:02 pmYes, the LUT stores effectively a "mapping" between function input and output value.Ideally, you want to precompute most of your data beforehand rather than calculating them in real time, now there are some scenarios where a real-time calculation is the only solution, but for most cases, there will be sufficient system memory to precompute.As you have no feedback, there is no way to accurately detect the stepper/servo position. Taking the derivative won't help you. You can use a counter to measure how many steps have occurred and thus the total angle/distance displaced. However, If the motor slips then that can never be corrected for (in usual runtime operating, you can force the motor to an extreme/hardstop to trigger a switch to indicate a home position). So when you use the LUT, you'll just have to pray that the motor does not slip so you get a 1:1 mapping of your LUT function.As per suggested prior, you can just use an array, ill walk through a basic example:Say I want to create a log LUT for an LED. I would have a function that resembles:Code:ledLut = {0, 0.69, 1.099, 1.39, 1.61};void ledLutFn(int i) {return ledLut;}What this does is effectively index an array and returns a value. As you may deduce, this only works for integer inputs.This LUT could either contain speed or position information, it's up to you.As for displaying to a screen, that is a task that can be solved through many methods. I'd suggest looking at the u8g2lib.https://github.com/olikraus/u8g2/wiki

author: paulca
author_rank: Super Contributor
timestamp: November 30, 2017, 10:28:56 am
content: If you look at the RC controller settings it more or less explains the formula you need to alter the rates.Expo, Limits and offsets.I would create a basic function which takes the parameters:getOutput( inputValue, expo, upperLimit, lowerLimit, offset ) {// Some exponential multiplier within the upper/lower limits// Add the offsetreturn outputValue}This gives you the curve within the limits with the centre offset by the offset value.Granted higher end radios do allow for multi-point curves which will require more mathematics.I am not entirely familiar with the microcontrollers, but you might run into issues if it does not support floating point mathematics. If that is the case, you would need to look up "fixed point" mathematics.

author: joker1283
author_rank: Newbie
timestamp: December 01, 2017, 01:39:33 am
content: Quote from: Nitrousoxide on November 30, 2017, 10:12:39 amThanks. I understand the idea of an LUT. I just need help on how to actually use it. Let's say the LUT contains position information (my preferred approach), and let's say the LUT looks something like this:input position output position0 01 12 43 94 16... and so forth.The input position is given by how much the rotary encoder ans turned. The output position is given by how much the stepper motor has turned. Let's ignore scaling and the transformation between linear and rotational motion for now.Initially both the input and output position are at "0". Suppose at time T1, the input position is at 1, the system will look at the LUT and realizes the output needs to be at 1 also. Does my code quickly turn the stepper motor and stops once it has turned enough steps corresponding to position 1 (at the output)? Then quickly after, the input position is at 2. According to the LUT, the output position needs to be at 4. If my stepper motor rotational speed (step/second) is the same, then it'll take longer to reach 4, so I would need to step faster to reach 4 if I don't want the output to "fall behind" the input too much. So maybe in my code I would need to periodically calculate the difference between the current output position and the desired output position and set my step speed accordingly?So I guess the output will always lag the input right? As you can see, there are a lot of details that needs to be worked out given that I have a LUT, and this is the part I hope I can get some advice on.Thanks. I appreciate it.

author: Nitrousoxide
author_rank: Regular Contributor
timestamp: December 01, 2017, 03:54:22 am
content: Quote from: joker1283 on December 01, 2017, 01:39:33 amYes, the motor would take longer to arrive at the destination if the displacement is large enough, and thus you would need to delay any other system that relies upon the motor position after that delay has been completed.It depends on the rate that you are sending position commands to the motor driver/output, the delay would also depend on the mechanical inertia of the motor, say for different loads your motor might take less/more time to displace.Note:Be careful when you drive stepper motors too fast as they may skip steps.Quote from: joker1283 on December 01, 2017, 01:39:33 amWhat you just described is a closed loop control systemYou're monitoring the current, measured value and comparing it to the desired value which produces a known "error". This "error" value can be then fed through a compensator so find the optimum output value to correct for this "error".A closed loop control system will address the speed and displacement errors, both in transient and steady state. I'm fairly confident most motor systems are closed loop.To implement this properly, you would need a sensor on the motor output. You would not be able to implement this technique by just "counting" the motor steps in software (which is effectively just guessing) and subtracting it from the set value.

author: paulca
author_rank: Super Contributor
timestamp: December 01, 2017, 07:44:30 am
content: In RC the transmittor sends the required position to the servo (via the receiver) as PWM pulses. The server moves using a control feedback loop to the position it knows represents that pulse width. This is why (usually cheap) servo's often buzz as they get caught between two positions and oscillate. The advantage is, if you grab the servo and try and move it out of that position it will fight you to get back to it.They use a highly geared motor and a position sensor rather than a stepper motor per-sae. Depending on your application you need to consider the output motor needs to apply torque to achieve it's goal of moving something with sizeable force.I suppose in the line of thought of this thread the servo needs to know it's position, so it needs feedback within itself which I believe is done electronically and not digitally but the controller and receiver do not. They trust the servo goes where they tell it. Thus the when you look at the servo positions in an RC transmitter they are not telling you the position of the servo they are just telling you the commanded position and trusting the servo went were it was told.

author: macboy
author_rank: Super Contributor
timestamp: December 01, 2017, 02:40:28 pm
content: Quote from: joker1283 on November 25, 2017, 11:23:09 pmA rotary encoder is a bad idea for the input. The problem is with missed codes. What happens when it is turned too fast (or too slowly) to capture the movement accurately? In the normal usage scenario for a rotary encoder, this doesn't matter, as it has no absolute position. But you are confining it to a specific amount of rotation with the linear slider and rack and pinion apparatus, so you must know the absolute position. A rotary encoder is intended to be a "speed and direction of rotation" type sensor, not an absolute position sensor. Instead, use either a normal potentiometer with your rack and pinion, or get a linear/slide type potentiometer, which is much simpler still. Use the pot as a voltage divider to feed and A/D of the micro, and you will very easily know the absolute position of the slider.A servo is the easiest output device. That is because all of the motion control smarts are contained within the servo itself. All that you need to do to command it to move to a specific position is to supply a pulse of (nominally) between 1 ms and 2 ms width/duration. 1 ms is full left, 2 ms is full right, and 1.5 ms is the mid-point. Usually the pulse is sent at a rate of roughly 50 times per second. Different servos may accept more or less frequent updates than that, but 50 Hz is the norm.For the "curve", you have a lot of options. You could provide say 10 points of adjustment, and allow the user to move the input/output point away from the straight line. Then you must interpolate between points, either linearly or using some type of best-fit curve algorithm. Or you could do it with something like a power-law deviation, very similar to the "gamma" curve used for TVs and computer monitors.I'd suggest implementing a minimum first: the input (reading the pot's position), calculating some curve (that you define at compile time), and commanding the servo. Play with different curves/algorithms. Notice how using only 8 bits for the input and output will result in a "dead zone" near zero, but increasing to much greater resolution (especially for the output) will improve that. After you have that sorted these fundamentals, then move on to create some kind of user interface to allow a run-time modification of the curve.

author: paulca
author_rank: Super Contributor
timestamp: December 01, 2017, 04:28:47 pm
content: "Seen this, thought of you"https://www.bitsbox.co.uk/index.php?main_page=product_info&cPath=116_349&products_id=2927

author: joker1283
author_rank: Newbie
timestamp: December 04, 2017, 02:18:13 am
content: Quote from: macboy on December 01, 2017, 02:40:28 pmLet me get this straight. I thought the rotary encoder will tell you the pulses that corresponds to a certain degree of rotation and also the direction of rotation. Therefore, if you have a "home" position in your code, then you can count the number of pulses along with their directions to calculate an relative position right? For example, the user lines up the rack and pinion in a certain way, and calls this "home", he might even press a button to the micro controller to make this home, and the pulse count will be set to 0. Then we can know the relative position by simply keeping track of the pulses from the rotary encoder right? (assuming there are no missed code)Quote from: macboy on December 01, 2017, 02:40:28 pmI'm learning about servos now. So basically, you control a stepper by specifying the frequency of steps (each control signal corresponds to a "step", and you can specify how fast it steps, like by changing the delay between each step). So you only get to control the rotational velocity.But you can control the servo by specifying a position? In another word, the input signal will corresponds to a position and the servo will move there quickly without you having to worry about the velocity?Quote from: macboy on December 01, 2017, 02:40:28 pmThat's what I had in plan.Thanks

author: paulca
author_rank: Super Contributor
timestamp: December 04, 2017, 09:36:49 am
content: Quote from: joker1283 on December 04, 2017, 02:18:13 amPretty much yes. It will also try and remain there as long as you keep sending the pulse width. You can try and move the servo away from that position and it will do whatever it can to remain or move back to that exact position. If you stop sending the signal (most) will go limp and might even go random and jittery. There are a few with memory which will still hold their last position even when you remove the input signal.

author: macboy
author_rank: Super Contributor
timestamp: December 05, 2017, 04:18:54 pm
content: Quote from: joker1283 on December 04, 2017, 02:18:13 amAgain the problem is missed codes, either from going too quickly or too slowly.Try an experiment: Find something with a rotary encoder, say the cursors position control of a digital oscilloscope, or the volume control of some home theatre receiver. Put the cursor (or volume) at some level. Mark the position of the knob against the faceplate with some tape. Now spin it back and forth multiple times at various speeds, fast and slow. Return to original marked position. Is the cursor (volume) now set exactly where it was when you started?QuoteYes. You move a stepper in steps. The speed is determined by the speed of stepping it, but the position is (hopefully) determined by the actual count of the steps. If you go 100 one way then 100 the other, no matter the speed, you should end up at the original position. If the motor is loaded down too much or you try to step too fast, it might miss some steps then you have a similar situation to the rotary encoder.A hobby servo has a geared-down motor, a position sensor (potentiometer), and control logic to move it to the desired spot. It will move to the new position as fast as possible. They have a speed rating which is in seconds per 60 degrees of rotation, and a torque rating. You control it by telling it the desired position, encoded as a pulse length as described above. There are many resources to learn more, as these are increasingly common on robotics in addition to R/C applications. As paulca mentioned, most will stop powering the motor (go limp) if/when the control signal pulses stop coming in. Others might self-center or poorly designed ones might go hard CW or CCW.Servos are very easy to control with a microcontroller. You just set up a PWM output to give a repeating pulse at the desired width. Of course there are many Arduino libraries out there, and examples for probably any other architecture. There are also ICs which control multiple servos without the contant work from the micro, you just send commands over I2C and it takes care of generating the pulse train for each servo. (search evilbay for "arduino 16 channel servo" for example).