-
Notifications
You must be signed in to change notification settings - Fork 10
Adds a guide with advanced usage for the servo module #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ekolker
wants to merge
26
commits into
master
Choose a base branch
from
ek-hw
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
15b5172
Create servo-pca9685-hacks.md
ekolker 9b7dc26
tech notes and commanding servos
ekolker 70defa7
added analog control section
ekolker 77f2c59
title formatting
ekolker 26d44df
digital control section
ekolker 72f96fb
mostly formatting
ekolker 173d779
added h-bridges
ekolker 4737b8f
typo
ekolker 4d9171d
small LEDs
ekolker 68d846f
better title
ekolker 62b2cea
strips, hack(s)
ekolker 0e6a374
explanation for technical notes
ekolker 730a2b3
reboot
ekolker 083d1f5
calibration tutorial
ekolker bd7e769
calibration tutorial, better highlights
ekolker d1db98b
tech notes tweak
ekolker 875a010
typo, clarity
ekolker 8bca7e1
clarity
ekolker 7b87967
./.. won't work by default
ekolker 6ff2a71
started dc motors
ekolker 49408b4
motor tutorial complete
ekolker 43b1788
links?
ekolker 4203014
links...
ekolker 108140d
edits
ekolker 5ade653
tightened up the intro
ekolker 2e690f4
tighter
ekolker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| # Using the Servo Module with LEDs, big motors, and more | ||
|
|
||
| **Read this whole section before moving on.** | ||
|
|
||
| The servo module is one of the most versatile modules you can use with Tessel. The [chip at its center is actually an adjustable PWM controller designed to control LEDs](http://www.nxp.com/documents/data_sheet/PCA9685.pdf) that we repurposed to be a servo driver. What this means is that it's easy to use for lots of applications besides just driving servos. | ||
|
|
||
|  | ||
|
|
||
| Everything in the image above and in the list below can be done with the servo module. | ||
|
|
||
| * [Command and provide power to RC/hobby servos of all shapes and sizes](http://start.tessel.io/modules/servo) | ||
| * [Calibrate each channel to get the most out of the hardware](#calibrate-your-servo). | ||
| * [Control arbitrary actuators through an external motor controller](#Arbitrary-actuators). | ||
| * [Control LEDs of all shapes and sizes, including their brightness, blink speed, blink frequency](LINK COMING SOON). | ||
|
|
||
|
|
||
| Below are a series of tutorials to help get you up and running. **No matter what you want to do in the end, take the time at the beginning to [calibrate your hardware as described below](#calibrate-your-servo) to make sure it gets used to its full potential.** | ||
|
|
||
| --- | ||
|
|
||
| ### Technical notes | ||
|
|
||
| The following is a list of useful information about the servo module. If you know your way around hardware, most of the tutorials can be deduced from these facts and numbers. | ||
|
|
||
| * The power and ground on the Servo Module are shared across all servos. Ground is common with the Tessel. | ||
| * The [barrel jack](http://www.cui.com/product/resource/pj-202a.pdf) is rated to 2.5A, but the [headers](http://media.digikey.com/PDF/Data%20Sheets/Sullins%20PDFs/z%20RzCzzzSzzN-RC,%20ST,11635-B.pdf) are rated to 3A apiece | ||
| * The duty cycle of each of the 16 channels is individually adjustable | ||
| * The PWM frequency is common for the entire chip (all channels) | ||
| * The drive strength of the chip is 25mA sink, 10mA source per channel at 3.3V | ||
| * The phase of each channel is adjustable via I2C commands, but not presently through the `servo-pca9685` library | ||
| * The library provides functions which allow you to control the max and min duty cycle of each individual channel. [This script](https://github.com/tessel/servo-pca9685/blob/master/examples/calibrate.js) is super handy for finding your specific actuator/controller's bounds. | ||
|
|
||
| ## Calibrate your servo | ||
|
|
||
| The protocol used to command servos is very lenient. The advantage to this is that it makes interfacing with such devices very easy. The cost is, or at least can be, precision. Each servo and motor controller will behave a little differently, and if you really want to command a precise, known position or speed, you should calibrate your device. Before reading further, you should familiarize yourself with the [servo protocol](http://www.rcheliwiki.com/Servo_protocol). This tutorial doesn't touch the PWM frequency because the servo module uses the servo protocol's standard 50Hz by default. Adjusting the PWM frequecy is covered in the [LED tutorial](LINK GOES HERE). The process for calibrating motor controllers is similar, and discussed in more detail [later on in this document](#calibrating-the-controller). | ||
|
|
||
| Open [calibrate.js](https://github.com/tessel/servo-pca9685/blob/master/examples/calibrate.js)/copy and save the code below and run using `tessel run ./your/path/to/calibrate.js`. The code allows you to find the PWM duty cycle numbers that correspond to full forward, full reverse, and the neutral point by typing numbers into the command line and watching the result. | ||
|
|
||
| ```js | ||
| var tessel = require('tessel'); | ||
| var servolib = require('servo-pca9685'); | ||
|
|
||
| var servo = servolib.use(tessel.port['A']); | ||
|
|
||
| var servoNumber = 1; // Plug your servo or motor controller into port 1 | ||
|
|
||
| // Reenable the console | ||
| process.stdin.resume(); | ||
| console.log('Type in numbers between 0.0 and 1.0 to command the servo.'); | ||
| console.log('Values between 0.05 and 0.15 are probably safe for most devices,'); | ||
| console.log('but be careful and work your way out slowly.'); | ||
| servo.on('ready', function () { | ||
| // Start at a duty cycle of 10% | ||
| var duty = 0.1; | ||
| // Set the min and max duty cycle to 0% and 100%, | ||
| // respectively to give you the maximum flexibility | ||
| // and to eliminate math | ||
| servo.configure(servoNumber, 0, 1, function () { | ||
| // Move into the starting position | ||
| servo.move(servoNumber, duty); | ||
| // Enter command positions into the command line. Work | ||
| // your way outwards until the servo begins to stall | ||
| // (or the motor velocity remains constant). Note the | ||
| // max an min values and use them in this *physical* | ||
| // motor/controller channel's `configure` call. | ||
| // Once you configure the motor, arguments to `move` of | ||
| // 0 and 1 will correspond to the minimum and maximum | ||
| // PWM values given in the `configure` call, thereby | ||
| // allowing you to easily command the actuator through | ||
| // its full range of motion. | ||
| process.stdin.on('data', function (duty) { | ||
| duty = parseFloat(String(duty)); | ||
| console.log('Setting command position:', duty); | ||
| servo.move(servoNumber, duty); | ||
| }); | ||
| }); | ||
| }); | ||
| ``` | ||
|
|
||
| After you've plugged everything in and run the code, the servo might look something like this when commanded with the script's default 10% duty cycle: | ||
|
|
||
|  | ||
|
|
||
| Play around with the console to try out different values. Work your way slowly outwards to minimize the risk of damaging the servo by stalling out, drawing too much current, and frying something. Your servo is stalling if you can hear it trying to move but failing to. This happens when the servo is under heavy load ("working really hard"), and will happen when the servo runs into its built-in mechanical stops at the limits of its range of motion. When it happens, you should be able to hear the motor inside the servo struggling. | ||
|
|
||
| For reference, I found that this particular servo had lower and upper limits of 0.0275 (2.75%) and 0.1225 (12.25%), which allowed it to move through its full range of motion: | ||
|
|
||
|  | ||
|
|
||
|  | ||
|
|
||
| Once you've found values that work nicely for a particular physical servo or motor controller, save them! | ||
|
|
||
| ##### **The command [`servo.configure( whichServo, minPWM, maxPWM, callback() )`](https://github.com/tessel/servo-pca9685#api-servo-configure-whichServo-minPWM-maxPWM-callback-Sets-the-PWM-max-and-min-for-the-specified-servo) maps the given max and min PWM values to 1.0 and 0.0, respectively, thereby making it easy to command two different devices to equivalent states.** | ||
|
|
||
| In the case of the values I found, the call would look like this: | ||
|
|
||
| ``` | ||
| servo.calibrate(1, 0.0275, 0.1225, function () {//callback goes here}); | ||
| ``` | ||
|
|
||
| I could then call `servo.move(1, 0)` to set the servo to the lower extreme and `servo.move(1, 1)` to move it to the other extreme. | ||
|
|
||
| ## Arbitrary actuators | ||
|
|
||
| Just because your motor doesn't have a "servo connector" doesn't mean it can't be used with Tessel. Everything in the image below is Tessel compatible! | ||
|
|
||
|  | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section is unclear because it's not very actionable. If you find yourself with a motor of this type, what might you try? Where would you look for more information? |
||
| *Pictured: a servo power adapter (5V, 1A), a Tessel, a servo module, a small brushed DC gear motor (with clutch and plastic gear mounted), a brushed DC motor controller ([Sabertooth 2x60](http://www.dimensionengineering.com/products/sabertooth2x60)), a standard servo (the one that ships with the servo module), a micro servo, some 0.1" male to female jumper wires, a small scredriver (for hooking things up to the motor controller), a 6" micro USB cable, and a brushed DC wheelchair motor.* | ||
|
|
||
| ### First things first | ||
|
|
||
| The first step to being able to control something is picking the actuator, and the second step is picking the controller. In this case, I have a small gear motor and a very large wheelchair motor. Both are brushed DC motors, so I'll be using the same controller, a [Sabertooth 2x60](http://www.dimensionengineering.com/products/sabertooth2x60) for both. To give you a sense of scale, the controller is overkill for the small motor but about right for the wheelchair motor in terms of its voltage, current, and power rating. I'll also be using the 12V bus of an ATX power supply to power the motor controller and, because old habits die hard, I've wired an E-Stop in and fused the wheelchair motor for good measure. | ||
|
|
||
| If your power source is a PC power supply like mine, you'll have to be careful about current surges, which happen when motors accelerate quickly. The supply I was using would shut itself off automatically if I stopped or started the wheelchair motor too suddenly, so I recommend starting small and calibrating the controller with a small motor if you have one on hand. I also recommend hooking everything up before you power anything on or run any code. It's also worth mentioing that you should **never** use the GPIO bank to power a motor or a motor controller. Appropriate use of the GPIO bank Vin pin can be found in [this document](./powering-tessel.md). | ||
|
|
||
| ### Setup | ||
|
|
||
|  | ||
|
|
||
| The setup for the small motor, above, looks a lot like the setup for the large motor, below. In both cases, power comes in at the bottom left of the frame and runs through the E-Stop (big red button) before connecting the to motor controller. The motor wires are connected to channel 1 on the motor controller. | ||
|
|
||
|  | ||
|
|
||
| Because the motor controller takes standard servo PWM pulses, wiring the control signal from the servo module was super easy: I connected the ground/0V pin on the Tessel (labeled "-" on the servo module) to that of the motor controller and routed the servo signal lines (labeled "S" on the servo module) to the signal input pins on the motor controller. Here's a [short video clip](https://s3.amazonaws.com/technicalmachine-assets/doc+pictures/servo-module-tutorial/motor_move.mov) of the big motor running you can download if you're curious (not much to look at, honestly). | ||
|
|
||
| ### Calibrating the controller | ||
|
|
||
| I began by calibrating the motor controller using the small motor and [calibrate.js](https://github.com/tessel/servo-pca9685/blob/master/examples/calibrate.js). In the case of DC motors, the PWM duty cycle typically maps to velocity, rather than to position as it does in servos. A minimum duty cycle (`servo.move(servoNum, 0.0)`) commands full reverse, a maximum duty cycle (`servo.move(servoNum, 1.0)`) commands full speed ahead, and the PWM duty cycle in the middle (`servo.move(servoNum, 0.5)`) commands no speed at all. | ||
|
|
||
| The trick, then is finding the duty cycles that maximize the range of commandable speeds but don't saturate the inputs to the controller. Suppose that the motor controller in question expects duty cycles from 6% to 13%, with 6% meaning "full reverse" and 13% meaning "full forward". If you were lazy and called 5% and 15% good enough, you would not only have an asymmetrical speed response (`servo.move(servoNum, 0.75)` would be a different speed than `servo.move(servoNum, 0.25)`), the midpoint PWM value set when you called `servo.move(servoNum, 0.5)` of 10% would have the motor drift forward ever so slightly, as opposed to stop. | ||
|
|
||
| If all else fails, a good way to achieve balanced, albeit not necessarily maximum, coverage of avaialable speeds is to find the midpoint and then offset the min and max PWM values symmetrically from tham point. This approach might be desirable from a control perspective. | ||
|
|
||
| ### Using your controller | ||
|
|
||
| It's best that the motors are stopped when the script starts and stops. Similarly, abrupt changes in velocity are not only physically jarring to the motor (and whatever it's connected to), but are also **much** more likely to damage electrical systems. Accelerate slowly and never go from full forward to full reverse all in one go. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does [this script] do? Clarify