Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Controlling servo in Elixir/Nerves
Masatoshi Nishiguchi
Masatoshi Nishiguchi

Posted on • Edited on

     

Controlling servo in Elixir/Nerves

I really wanted to control a servo motor using my favorite programming language Elixir. Here is what I learned when I did experiments controlling aSG90-type digital servo motor from myNerves-poweredRaspberry Pi Zero W usingPCA9685 PWM/Servo controller.

にほんご

Servo motors

I am not gonna talk about what a servo motor is since I am not an expert and also there are tons of good resources on the Internet, such as Sparkfun'sHobby Servo Tutorial andBasic Servo Control for Beginners.

Long story short, there are two types of servo motors available for hobby use:

Standard servo

e.g. SG90

standard_servo

Continuous-rotation servo

e.g. FS90R

continuous_servo

Pulse width modulation (PWM)

Pulse width modulation (PWM) is commonly used for controlling a digital servo. We control a servo by changing the ratio of on-time to off-time of the waveform.

PWM can be used forsmoothly dimming LEDs like this.

servo-driver-pwm-leds

PWM for servo motors

As far as I know, most hobby servos accept the 50Hz signal whose period is 20ms. What confused me was after that.
Many sources say:

  • 1.0ms pulse width for full clockwise
  • 1.5ms pulse width for neutral position
  • 2.0ms pulse width for full counterclockwise

but my SG90 moves far less than 180-degree range with that setting. It is kind of mysterious how many degrees the servo rotates for what pulse width. It seems like this guy had the same question:What is the proper calculation of duty cycle range for the sg90 servo? | https://raspberrypi.stackexchange.com

I am not sure whether those tutorials are wrong or different servos have different specifications. Anyway, I cannot find any solid information on detailed specifications of SG90-type servo. Please let me know if you have any information!

Here I put together my researches and observations.

pulse widthduty cyclememo
400µs2%my SG90's lower limit
500µs2.5%looks close to 0 degree to me
1500µs7.5%typically a neutral position (90 degrees)
2500µs12.5%looks close to 180 degrees to me; maybe like 170
2800µs14%my SG90's upper limit

Some documents say SG90 rated pulse ranges is 500..2400µs, but my SG90 can rotate between 400..2800µs.

Servo tester

Probably experts would use some machines to see the actual waveforms, but I do not want to dig that deep. I tried this inexpensive (~10 USD) servo tester and it was super useful in my understanding the characteristics of my SG90. It generates a signal changing the pulse width between 800..2200µs.

PWM controller

As a hardware noob, I asked Elixir/Nerves community questions about how to control a servo from Nerves-powered Pi. A few people includingFrank Hunleth co-author ofNerves project kindly gave me valuable advice. They recommend using an "I2C->PWM" board rather than using the Raspberry Pi's builtin PWM. Frank added that Linux PWM support is poor based on his past experience.

So I decided to usePCA9685: 16-channel 12-bit PWM controller, which I control from my Raspberry Pi Zero W that is powered byNerves IoT framework viaI2C. Having 16 channels means we can control 16 different servo motors simultaneously, which is cool despite being overkill for my experiments.

Libraries

I could not found any Elixir libraries for controlling a servo other thanjimsynz/pca9685.ex, which was unfortunately outdated and unmaintained.

So I decided towrite one on my own, readingPCA9685 data sheet and adopting ideas from existing libraries written in various programming languages. My servo kit is working pretty well so far.

For communicating between Raspberry Pi and PCA9685, I useelixir-circuits/circuits_i2c library, which is a reliable and established I2C library in Elixir community.

Demo

hardware

firmware

software

  • ServoKit - Use PCA9685 PWM/Servo Controller in Elixir

servo-demo

Here is a throw-away Elixir script I wrote, which I ran from the Interactive Elixir Shell on my Raspberry Pi.

# Start a pwm control processServoKit.start_link()# Define a function that changes duty cycle and delays a littleset_pwm_duty_cycle=fnx,ch->ServoKit.set_pwm_duty_cycle(x,ch:ch)Process.sleep(50)end# Iterate changing duty cycle with 0.5 step betweem 2.5 and 12.5 for channel 15list1=2.5|>Stream.iterate(&(&1+0.5))|>Enum.take(21)list2=12.5|>Stream.iterate(&(&1-0.5))|>Enum.take(21)0..99|>Enum.each(fn_->list1|>Enum.each(&set_pwm_duty_cycle.(&1,15))list2|>Enum.each(&set_pwm_duty_cycle.(&1,15))end)
Enter fullscreen modeExit fullscreen mode

That's it!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

たのしむ
  • Location
    🇯🇵
  • Work
    ソフトウエアエンジニア
  • Joined

More fromMasatoshi Nishiguchi

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp