We control servos from OpenWRT without Arduino

  • Tutorial

A short post on how to avoid unnecessary elements in a system with servos and use iron to the maximum


I have been sick with Linux, OpenWRT, network and wireless technologies, security for a long time and now, and now I have become slowly infected by robotics and smart homes. All this is very cool, especially when there are so many ready-made templates, free and open source code, and at times you can completely go to the evil side and quickly throw logic into Scratch.
But then interest wakes up no longer just blinking LEDs, the wow effect passes and it is necessary to solve applied problems. It seems that even here one should admire the abundance of the finished, but the devil, as always, is in the details. It's one thing to manage logicЕСТЬ/НЕТ, this makes it easy to turn the light on or off, you can even pick up the air quality sensor (MQ-135) and turn on the hood if necessary. All this is cool, but in the courtyard of the 21st century, spaceships plow the great theater and the soul asks for something cooler. My gaze fell on the control of servos. Why not? The topic is very broad, because they are present in many mechanisms, from robots to simple bottle openers. A plus is the fact that in aircraft the engines are controlled in the same way and this expands the range of use simply at times.

I invite

those interested to cat. Those who have long been familiar with the topic and want to go straight to the point - boldly skip to the " Step by Step " section .

Start over

To make the essence of this note clear to everyone, you should first pay attention to the components of the servo.


Electric motor, gearbox, potentiometer and controller. Everything ingenious is simple, isn't it?

Pulse width modulation or PWM is used to control the servo drive. Nothing complicated, it's just a signal in the form of rectangular pulses. The main parameters are pulse width and pause width. "Pause", or better to call it correctly - period, sets the frequency of the signal. Say, if we have a period width of 100 ms, then the frequency will be 10 Hz. It is very simple to calculate: we translate milliseconds into seconds and divide the unit by this number. Accordingly, 100ms = 0.1s and if 1 is divided by 0.1 we get 10. You can check on the calculator.

The pulse width sets the angle of rotation of the servo, and in the case of aircraft motors sets the speed and direction of rotation.
Schematically, it looks something like this:

And on an oscilloscope like this:

Now let's talk about how the servo perceives such a signal. And the devil is creeping up quietly with details.
The fact is that the controller can be digital or analog.
If it’s quite simple, the difference is that the analog controller supplies or does not supply voltage only at the time of the pulse. By setting the pulse interval to 40, 120, or, say, 240 ms, you can notice how the servo starts to “twitch” during operation. That's because the microcircuit is inside and the frequency of the entire servo drive is equal to the frequency of the external signal. The standard 20 ms is 50 Hz, 40 ms is 25 Hz, and by analogy. Accordingly, voltage is supplied (or not supplied) to the motor 50 or 25 times per second. By lowering the frequency, you can significantly reduce the torque and achieve a slower operation of the mechanism, though at the cost of the “twitching” already described.
Digital controllers, as a rule, are a small microprocessor with a strapping. The key difference from the analog microcircuit is that the internal frequency of operation is constant. You can reduce the frequency of the control signal as much as you like, this will only affect the reaction time, but the torque will be constant. Although, giving out a change in position at long intervals and in small portions, you can achieve a slow speed of rotation. It already depends on the specific servo and its parameters.

How to generate a signal?

For this, they usually use some kind of microcontroller, they have a special love for the Arduino platform. Everything is simple there. A ready-made library is used, we feed the signal parameters to the desired function and get pulses at the specified GPIO of the desired width.
But what if there is no way to use a microcontroller that is paired with the main device, and the power of the controller itself for solving problems, well, is it not enough? It remains to look for alternative options. And I have such!
As already clear from the title, the OpenWrt operating system will be used. Which is essentially a full-fledged Linux kernel distribution. And this gives ample opportunities and flexibility of customization. OpenWrt and its derivatives are actively used in various "smart home" systems, but more on that in another article. How to generate a PWM (or bourgeois PWM) signal? It turns out that not much more complicated than on Arduino. To do this, you need to use the same GPIOs, and instead of the library, a kernel module called PWM-GPIO-Custom. The last stable version of OpenWrt where it works is 12.09, but I spent about a week trying to get it to work on the current Trunk to understand this. I don’t know for what reason, but there is no package with this module in the official repository and you have to assemble it yourself, but it’s not so difficult. Below I will write how.

Step-by-step instruction

So, for starters, we need to download the OpenWrt build toolkit. Although, to be completely honest, you need to start by installing Linux, but I hope that many of you have already completed this point.
So, you created a folder for the toolkit, switched to it . You
can download the sources using the command
git clone git://git.openwrt.org/12.09/openwrt.git
. You also have a terminal at the bottom of the window, right?
Sorry, this is very convenient.

After downloading, you need to go to the openwrt folder and download packages using the command
git clone git://git.openwrt.org/12.09/packages.git

Now we have all the source codes for the packages. But wait ... But what about pwm-gpio-custom? He is not there.
Do not despair, here it is.
You just need to unzip the contents in openwrt / package and everything will be fine.

Now we pass directly to the assembly.
Being in the openwrt folder, you need to execute make -j n kernel_menuconfig
Instead of n, you need to substitute the number of your cores + 1.
A blue menu will open. Select the item Device Drivers.

Find PWM Support:

Activate the item PWM emulation using GPIO. Choose a space. We need stars everywhere, this is important:

After that, you need to reconfigure the kernel a little. We are looking for the appropriate item:

Put an asterisk on the item High Resolution Timer Support, set the Timer frequency to 1000HZ, and in the Premption Model parameter select Low-Latency Desktop: You

must know the hardware platform of your router. But more importantly, specify it in the configuration. I have this Atheros ar71xx:

The required kernel configuration is complete. Now, as soon as you click the final Exit, the system will ask you whether it is worth saving the changes, and you need to answer in the affirmative.

Now you need to configure the assembly by the command in the same way. make -j n menuconfig

Then, in the Kernel Modules menu:

Select Other modules:

And put an asterisk on kmod-pwm-gpio-custom:

That's it, you can proceed with the assembly. All the same team. make -j n

It remains to lean back and see something, you can drink tea / coffee, the assembly process is not fast.
Once the build is complete, you can go to the bin folder. It will have a folder with your platform and images. You can flash in full accordance with standard instructions. As soon as the firmware process is completed, you can safely go through telnet. It will be necessary to additionally download the kmod-pwm-gpio-custom package to the device itself. This can be done through SCP, or through wget, or install openssh-sftp-server and use FileZilla.

It is better to download the package itself to the / tmp directory, since the ROM is not rubbery, and this directory is physically located in RAM, which is usually from 32 to 64 Mb. After downloading, the package must be installed with the command opkg install /tmp/kmod-pwm-gpio-custom_xxx.ipk.You can not bother with the name of the package, TAB auto-completion works great.

PWM signal generation

After installing the package, you can proceed to direct control of the GPIO and the generation of the PWM signal.
To do this, you need to activate the kernel module. You can make it a team. insmod pwm-gpio-custom bus0=0,23 bus1=1,20
This is just an example of how it can be. busX sets the number of the bus that can be controlled through the character device under this same number in /sys/сlass/pwmus. Two of them will appear: gpio_pwm.0: 0 and gpio_pwm.1: 0 . You can manipulate the PWM parameters by simply writing the corresponding variables to the files. Yes, I almost forgot, all values ​​are set in nanoseconds. Let's go:

echo 10000000 > /sys/class/pwm/gpio_pwm.0\:0/period_nsSets the period. In this case, it is 100 Hz.
echo 8500000 > /sys/class/pwm/gpio_pwm.0\:0/duty_nsSets the duty cycle.
Yes, some conclusions are inverted by default and you need to set the time of the “void” inside the period. If the High value for GPIO is 1, then you need to set. echo 1500000 > /sys/class/pwm/gpio_pwm.0\:0/duty_nsThe time of the pulse itself will be indicated.
You can check it empirically. Maybe I will find or someone will tell you a way to do it more beautifully =)
Now it remains only to activate the signal.
echo 1 > /sys/class/pwm/gpio_pwm.0\:0/runAnd we get something like this on the oscilloscope.

If you connect a servo cable to the PWM pin, it will get exactly in the center position. Of course, power must also be connected.


In this way, a signal can be generated at a frequency of 200 Hz, which means that the reaction time for one drive will be reduced to 5 ms. For opening and closing the lock, it may not be critical, but for aircraft it will be very important. I hope that in the near future I will get a motor and a controller, or a good reader from the city of Yekaterinburg will agree to lend me such an experiment and a second article will appear.
Thank you for reading to the end. For a snack, let me introduce you a little video.

Demonstration of work. Two channels tuned to the far right and far left positions.

Video demonstration of the PWM signal.


I want to express my deep gratitude to the author of the Claudio Mignanti module , who answered by mail and clarified the necessary questions.

The circuit of the servo drive and control signals were taken on wiki.amperka.ru .

If you have any additions or wishes - write in the comments.

UPD: a5b is interested in what kind of device was used. Well, this is no secret. The board is a Chinese counterpart to the EL-M150. The processor inside is the Atheros AR9331.
It is used very widely in such common routers as mr3020 or wr703n.
The board looks as follows.

Also popular now: