<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Principia Labs &#187; serial</title>
	<atom:link href="http://principialabs.com/tag/serial/feed/" rel="self" type="application/rss+xml" />
	<link>http://principialabs.com</link>
	<description>design, build, test, iterate.</description>
	<lastBuildDate>Sun, 28 Mar 2010 16:38:22 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Arduino-Python 4-Axis Servo Control</title>
		<link>http://principialabs.com/arduino-python-4-axis-servo-control/</link>
		<comments>http://principialabs.com/arduino-python-4-axis-servo-control/#comments</comments>
		<pubDate>Tue, 08 Apr 2008 18:46:29 +0000</pubDate>
		<dc:creator>Brian</dc:creator>
				<category><![CDATA[electronics]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[serial]]></category>
		<category><![CDATA[servo]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://principialabs.com/?p=69</guid>
		<description><![CDATA[Although the Arduino platform is ideal for standalone applications, it really comes to life when interfaced with a PC. Connect Arduino to a personal computer and you instantly add a ton of versatility and processing power to your project. This tutorial will describe how to use Arduino to control a bank of four independent RC [...]]]></description>
			<content:encoded><![CDATA[<div class="video">
<embed src="http://blip.tv/play/wkew8g0C" type="application/x-shockwave-flash" width="380" height="310" allowscriptaccess="always" allowfullscreen="true"></embed>
</div>

<p>Although the <a href="http://arduino.cc/">Arduino</a> platform is ideal for standalone applications, it really comes to life when interfaced with a PC.  Connect Arduino to a personal computer and you instantly add a ton of versatility and processing power to your project.</p>

<p>This tutorial will describe how to use Arduino to control a bank of four independent RC servos with your PC (or Mac, or *nix Box), using a USB cable and a modular Arduino-Python software stack.</p>

<p>The following discussion builds upon concepts presented in two previous articles, &#8220;<a href="/arduino-serial-servo-control/">Arduino Serial Servo Control</a>&#8221; and &#8220;<a href="/joystick-control-of-a-servo/">Joystick Control of a Servo</a>.&#8221;  As always, comments, critiques, or suggestions for improving or adapting this code are welcome and appreciated.</p>

<h4>Project Outline</h4>

<p>The primary goal for this project was to create a software stack that allows simple and flexible control of multiple servos from any type of Python script.</p>

<p>The solution has two basic components: (1) an Arduino sketch that waits for serial input from a connected PC, then moves each servo to its commanded position, and; (2) a Python module on the PC that opens the serial connection and formats the data packets expected by the Arduino.</p>

<p>Any other Python program written to sit on <em>top</em> of these two layers need not worry about the messy details of serial communication, but rather can just say something like, &#8220;Move servo #2 to 90 degrees.&#8221;  Or, more precisely:</p>

<pre><code>servo.move(2,90)
</code></pre>

<p>Easy, right?  Let&#8217;s get started.</p>

<p><span id="more-51"></span></p>

<h2>Part I:  Smoke, Mirrors, and Hand-Waving</h2>

<p>If you just want to get things up and running quickly, start here.  These instructions will get your servos connected and obeying every whim of your PC in no time.</p>

<h4>Hardware Setup</h4>

<p>Hardware for this project consists of an Arduino module, four <a href="http://www.horizonhobby.com/Products/Default.aspx?ProdID=JSP20050">JR Sport ST47</a> standard servos, and a breadboard to create the circuit.</p>

<p>The servos each have three wires: Ground (brown), Power (red) and Control (yellow).  Each of the Control wires will connect to a different digital pin on the Arduino board (pins 2 through 5 in our setup), and <em>all</em> of the Power and Ground wires will need to connect somehow to the 5V and Gnd pins.</p>

<div style="text-align:center;"><a href='http://principialabs.com/wp-content/uploads/arduino-breadboard.jpg'><img src="http://principialabs.com/wp-content/uploads/arduino-breadboard.thumbnail.jpg" alt="" title="Breadboard: click to enlarge" /></a></div>

<p>The simplest way to accomplish this is to create a &#8220;bus&#8221; bar along one of the breadboard&#8217;s edges, as shown in the photo above. Simply route the Arduino&#8217;s 5V and Gnd to a convenient area on the breadboard, and connect all the servos.</p>

<h4>Required Software: The Lower Layers</h4>

<p>To get the effects seen in the video above, you&#8217;ll need at least the following two programs.  Although this code is designed to control four servos, it also works as-is with <em>fewer</em> servos, and &#8212; with a few modifications &#8212; as many as twelve (or 48 with the <a href="http://arduino.cc/en/Main/ArduinoBoardMega">Arduino Mega</a>!).</p>

<p><strong>Download the code:</strong></p>

<div style="padding-left:20px;">

<p><del><b>MultipleServos.pde</b>: This is the Arduino sketch.  Copy and paste this code into your Arduino software and upload it to the board.</del></p>

<p><a href='http://principialabs.com/wp-content/uploads/MultipleSerialServoControl.pde'><b> MultipleSerialServoControl.pde</b></a>: [Updated 12/23/09] This is the NEW Arduino sketch, which uses the Arduino <a href="http://arduino.cc/en/Reference/Servo">Servo library</a> to make alterations <i>much</i> simpler.  You can control up to 12 servos using this code (with modifications) and most Arduino boards, or <i>up to 48 servos</i> using an Arduino Mega!  (See the code comments for specific details.)  This code should also solve most of the servo &#8220;jitter&#8221; issues mentioned in the comments below.  Copy and paste this code into your Arduino software and upload it to the board.  (Requires <a href="http://www.arduino.cc/en/Main/Software">Arduino 0017</a> or greater.)</p>

<p><a href='http://principialabs.com/wp-content/uploads/servo.py'><b>servo.py</b></a>: This is the Python module which talks directly to the above Arduino sketch.  This script requires the <a href="http://sourceforge.net/projects/pyserial/">pyserial</a> module, available from Sourceforge. Save this script on your PC wherever you like, just be sure to name it &#8220;servo.py&#8221;.</p>

</div>

<div class="help">
<b>New to Python?</b> Welcome!  Python is a versatile and fun language to learn, and it&#8217;s used by just about everyone, from newbies to NASA!  Check out the <a href="http://wiki.python.org/moin/BeginnersGuide">Beginner&#8217;s Guide</a>  to get your bearings, or get the full skinny at <a href="http://python.org/">python.org</a>.
</div>

<p><strong>Customize the code:</strong></p>

<p>Depending on your computer system and Arduino hardware setup, you may need to make a few modifications to the code.</p>

<p><strong>Arduino:</strong> In the &#8220;MultipleSerialServoContro&#8221; sketch, take note of the following variables and make adjustments as necessary for your setup.  See &#8220;<a href="/arduino-serial-servo-control/">Arduino Serial Servo Control</a>&#8221; for more details regarding the <code>minPulse</code> and <code>maxPulse</code> variables.  (If you&#8217;ve got standard RC servos attached to pins 2-5, you probably won&#8217;t have to change anything.)</p>

<pre><code>// Common servo setup values
int minPulse = 600;   // minimum servo position, us (microseconds)
int maxPulse = 2400;  // maximum servo position, us

// Attach each Servo object to a digital pin
servo1.attach(2, minPulse, maxPulse);
servo2.attach(3, minPulse, maxPulse);
servo3.attach(4, minPulse, maxPulse);
servo4.attach(5, minPulse, maxPulse);
</code></pre>

<p><strong>Python:</strong>  In the &#8220;servo.py&#8221; script, you&#8217;ll most likely need to change the value of the <code>usbport</code> variable, which tells Python how to find your Arduino (On Windows, it&#8217;ll be something like &#8216;COM5&#8242;. On a Mac, &#8216;/dev/tty.usbserial-xxxxx&#8217;.  On Linux, &#8216;/dev/ttyUSB0&#8242;.).  Try running <code>ls /dev/tty*</code> from a Mac or Linux terminal for a list of available ports.  [ToDo: Modify the script to make this step unnecessary.]</p>

<p><strong>Test the code:</strong></p>

<p>Once your hardware is set up and the software is installed, you can test the system&#8217;s basic functionality from the <a href="http://programming-crash-course.com/the_python_interactive_interpreter">Python interactive interpreter</a>, like so:</p>

<pre><code>~/path/to/servo.py$ python
&gt;&gt;&gt; import servo
&gt;&gt;&gt; servo.move(2,150)
</code></pre>

<p>The <code>servo.move()</code> method takes two arguments, both integers.  The first is the servo number you wish to move, 1-4 (or whatever).  The second is the commanded angular position of the servo horn, from 0-180 degrees.  So, if you want to move Servo #3 fully clockwise (180 degrees), you&#8217;ll type <code>servo.move(3,180)</code>.  Cake, baby!</p>

<h4>Optional Software: From Totally Geek to Totally Chic</h4>

<p>The following scripts are designed to leverage the functionality of the <code>servo.move()</code> method for simple and readable code.  Make sure these files reside in the same directory as &#8220;servo.py&#8221;.</p>

<ul style="list-style-type: none; padding-left: 20px;">

<li><a href='http://principialabs.com/wp-content/uploads/servodance.py'><b>servodance.py</b></a>:  A cascading effect that feels like watching a quarter spiral down one of those funnel-shaped wishing wells.</li><br />

<li><a href='http://principialabs.com/wp-content/uploads/servorandom.py'><b>servorandom.py</b></a>: The final servo sequence seen in the video, with individual servos moving to random positions and then waving &#8220;goodbye&#8221; in unison.</li><br />

<li><a href='http://principialabs.com/wp-content/uploads/servomarch.py'><b>servomarch.py</b></a>:  This one&#8217;s not in the video, but it&#8217;s a fun script to test individual and simultaneous movement of multiple servos.  Just set the number of servos to march (default is 4), and send them off!</li><br />

<li><a href='http://principialabs.com/wp-content/uploads/multijoystick.py'><b>multijoystick.py</b></a>: Allows joystick control of four servos, with each joystick axis controlling a single servo.  This script is the most complex, so try getting the first three working, then graduate to this one &#8212; it&#8217;s easier to troubleshoot problems that way.  <br/>[Note: This script also requires installation of the <a href="http://www.pygame.org/">pygame</a> module.]</li>

</ul>

<p>With any luck, you should now have everything up and running just like in the video!</p>

<h4>NEW: Adding Servos</h4>

<p><p>[Updated 12/23/09] If you&#8217;re using the <a href='http://principialabs.com/wp-content/uploads/MultipleSerialServoControl.pde'>new Arduino sketch</a>, you can easily add servos to your project by making a few simple additions to the code.  The beauty of this system is that <code>servo.py</code> can remain unchanged, and all of the higher-level Python scripts just need simple alterations to include whatever number of servos you decide to add.  This segment will outline how to change the Arduino sketch; changes to the Python scripts will be up to you!</p>

<p>There are three places in the <code>MultipleSerialServoControl</code> sketch where you&#8217;ll need to make additions, if you want to control more than four servos.  Each section of the code contains the comment &#8220;TO ADD SERVOS:&#8221; followed by a suggestion on what to add.  </p>

<p>First, add a Servo object for each additional servo:</p>

<pre name="code" class="arduino:nocontrols">
// Create a Servo object for each servo
Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
// TO ADD SERVOS:
//   Servo servo5;
//   etc...
</pre>

<p>Second, assign a digital pin to each additional servo:</p>

<pre name="code" class="arduino:nocontrols">
  // Attach each Servo object to a digital pin
  servo1.attach(2, minPulse, maxPulse);
  servo2.attach(3, minPulse, maxPulse);
  servo3.attach(4, minPulse, maxPulse);
  servo4.attach(5, minPulse, maxPulse);
  // TO ADD SERVOS:
  //   servo5.attach(YOUR_PIN, minPulse, maxPulse);
  //   etc...
</pre>

<p>Third, create a new switch case for each additional servo:</p>

<pre name="code" class="arduino:nocontrols">
      // Assign new position to appropriate servo
      switch (servo) {
        case 1:
          servo1.write(pos);    // move servo1 to 'pos'
          break;
        case 2:
          servo2.write(pos);
          break;
        case 3:
          servo3.write(pos);
          break;
        case 4:
          servo4.write(pos);
          break;
   // TO ADD SERVOS:
   //     case 5:
   //       servo5.write(pos);
   //       break;
   // etc...
      }
</pre>

<p>After making changes, be sure to click the &#8220;Verify&#8221; button on your Arduino software to make sure there are no errors, then upload it to the board.  Test your changes by calling the <code>servo.move()</code> method from the Python interpreter.  That&#8217;s it!</p>

<div style="border-top:1px solid #ddd;margin:40px 140px;">
</div>

<h2>Part II:  Getting Down to Brass Tacks</h2>

<p>Next, let’s take a look under the hood to see how it all works.  If you&#8217;re the type that just wants to get things working and damn the details, <strong>STOP HERE</strong>.  Otherwise, continue on, and I&#8217;ll do my best to explain how the code &#8220;do what it do.&#8221;</p>

<h4>The Problem Set</h4>

<p>Asynchronous serial communication is not perfect.  Sometimes there are errors,  dropped packets, confusion.  Sometimes the mail does <em>not</em> get through.  In both of the previous two serial/servo projects, the Arduino expected only one byte from the PC, and in both cases that byte represented a commanded servo position &#8212; and nothing more.  If a byte was missed or skipped, it wasn&#8217;t a big deal, another one was sure to come along, and it was impossible to misinterpret.</p>

<p>This project presents a couple of new challenges.  First, we are controlling more than one servo, so the Arduino needs more than one command element for each move.  As we&#8217;ve seen above, it needs to know (at least) <em>which</em> servo to move, and <em>how much</em> to move it.  Secondly, we have the problem of communication.  This time, we&#8217;re sending <em>two</em> command elements for each move (servo number &amp; position), and these elements are clearly <em>not</em> interchangable. That is, if we want to send <code>servo.move(4,90)</code>, we need to make sure that Arduino knows that the &#8217;4&#8242; means &#8220;Servo #4&#8243; and the &#8217;90&#8242; means &#8220;90 degrees.&#8221;</p>

<p>Tom Igoe&#8217;s article, &#8220;<a href="http://www.tigoe.net/pcomp/code/serial-communication/interpreting-serial-data-bytes">Interpreting Serial Data</a>,&#8221; contains an excellent discussion of some of the problems involved in serial communication, and lists several issues that need to be addressed in every project, namely:</p>

<blockquote>
  <ol>
  <li>How many bytes am I sending? Am I receiving the same number?</li>
  <li>Did I get the bytes in the right order?</li>
  <li>Are my bytes part of a larger variable?</li>
  <li>Is my data getting garbled in transit?</li>
  </ol>
</blockquote>

<p>The Arduino&#8217;s <code>Serial.read()</code> function reads one byte of data at a time from its <em>serial buffer</em>.  Think of the serial buffer as a mailbox.  It&#8217;s a small (128 bytes) area of memory where incoming serial messages are stashed until the Arduino is ready to read them.  Every character we send from the PC to Arduino is one byte.  So, while we could send the Arduino something very unambiguous like, &#8220;Yeah, hi, Arduino, it&#8217;s the Linux Box again.  What&#8217;s happening?  If you could go ahead and move Servo #4 to the 90-degree position, that would be great.  Thaaanks,&#8221; (163 bytes) it&#8217;s obviously better if we can come up with something a little more terse.</p>

<p>However, as we&#8217;ve seen, if we just send over the characters &#8217;4&#8242;, &#8217;9&#8242;, and &#8217;0&#8242; &#8212; remember, each character is a byte &#8212; the Arduino might get confused.  This problem is amplified when more commands start stacking up in the buffer.  Let&#8217;s say now we command <code>servo.move(2,180)</code> and <code>servo.move(3,120)</code>.  Now the buffer should hold {4,9,0,2,1,8,0,3,1,2,0}, except&#8211;OOPS!&#8211;one of the bytes got dropped along the way, so now it holds {4,9,0,2,1,8,3,1,2,0}.  &#8220;Wait, which servo did you want me to move?&#8221;  You can clearly see a problem developing.</p>

<h4>Solution: Data Packets and Start Bytes</h4>

<p>Luckily, part of the solution is handled in the way Arduino communicates.  Arduino uses <a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> encoding to represent alphanumeric characters.  Each character sent over the wire is converted to the binary equivalent of a decimal value from 0 to 255.  [See this <a href="http://www.arduino.cc/en/Reference/ASCIIchart">conversion chart</a> for specifics.]</p>

<p>So, for example, if we send over the character &#8216;A&#8217;, Arduino recognizes this as its decimal value, &#8217;65&#8242;.  We won&#8217;t get too deep into this concept except to say that the implementation is <em>great</em> for our application, because as long as the values we&#8217;re sending are less than 255, they&#8217;ll fit neatly into one byte.  Since the largest value we send is 180, we only have to send two bytes per command.</p>

<p>Now, if you&#8217;ve looked at the ASCII conversion chart, you&#8217;ll recognize that doing this every time you want to send a command would be a real pain.  Also, trying to teach Python this chart would take up a lot of unnecessary code.  Thankfully, this problem is already solved for us with Python&#8217;s <code>chr()</code> function.  Wrap any decimal value from 0-255 in <code>chr()</code>, and you get back its ASCII equivalent.  A few examples:</p>

<pre><code>~$ python
&gt;&gt;&gt; chr(65)
'A'
&gt;&gt;&gt; chr(110)
'n'
&gt;&gt;&gt; chr(13)
'r'
&gt;&gt;&gt; chr(9)
't'
</code></pre>

<p>You get the idea, but notice that ASCII doesn&#8217;t just represent letters and numbers, but also symbols and other &#8220;control&#8221; or &#8220;non-printing&#8221; characters like line-feeds, returns, and tabs.</p>

<p>So, now if we want to send <code>servo.move(4,90)</code>, we only need <em>two</em> bytes, the ASCII equivalents of &#8217;4&#8242; and &#8217;90&#8242;, represented in Python as <code>chr(4)</code> and <code>chr(90)</code>, and interpreted by the Arduino sketch as, once again, simply &#8217;4&#8242; and &#8217;90&#8242;.  Easy!  [Seriously, if your brain explodes at this point, or you're bleeding from the ears, it's understandable.  I don't like it any more than you do, but stick with me, it'll all work out neatly in the end.]</p>

<p><strong>Packets, Headers, and Payloads</strong></p>

<p>Okay, great, now instead of just digits in Arduino&#8217;s serial buffer, we have meaningful values.  Part of the problem is solved, but we still haven&#8217;t addressed the issue of dropped or missing bytes.  That is, how will the Arduino know that a &#8217;4&#8242; is &#8220;Servo #4&#8243; and not &#8220;4 degrees&#8221; when pulling values out of a crowded buffer like {4,90,2,180,3,0,1,110} ?</p>

<p>The answer is <a href="http://computer.howstuffworks.com/question525.htm">data packets</a>.  Very simply, instead of just sending a long string of numbers to Arduino, we&#8217;ll send a very specific ordered message, a <em>packet</em> of values, that is intended to be read and interpreted <strong>as a whole</strong> and <strong>in order</strong>, or else discarded completely.</p>

<p>Now, the structure of a packet can be as simple or as complex as we need it to be, as you might have noticed if you followed that last link.  But all we really need is some means of ensuring that Arduino doesn&#8217;t confuse one value for another.</p>

<p>Essentially, our Python script needs to tell Arduino three things:</p>

<ol>
<li>Here comes a new servo command.</li>
<li>Servo number to move.</li>
<li>Commanded servo position.</li>
</ol>

<p>We&#8217;ve already been sending the last two elements, the servo number and position.  Here, we&#8217;re adding a third element, which we&#8217;ll call the <em>header</em> or the <em>start byte</em>.  Our header, like the rest of the data in our packet, will be just one byte long, and contain no real information other than the conceptual message, &#8220;I am a header.&#8221;</p>

<p>The <em>order</em> of this message is important.  Every packet sent over the wire, or read from the serial buffer, will now have the following format:</p>

<pre><code>(Header, Servo Number, Servo Position)
</code></pre>

<p>or, more tersely:</p>

<pre><code>(startbyte, servo, angle)
</code></pre>

<p>What to use as a startbyte?  Well, we&#8217;re only using the values from 0-180 as either our Servo Number or Servo Postion.  Any value from 181 to 255 would be unique.  We&#8217;ll use &#8217;255&#8242; just to make it obvious.  So, every packet will now look something like one of the following:</p>

<pre><code>(255, 1, 90)
(255, 2, 180)
(255, 3, 0)
</code></pre>

<p>And the Arduino&#8217;s serial buffer would look something like:</p>

<pre><code>{255,1,90,255,2,180,255,3,0}
</code></pre>

<p>Now, instead of reading byte after byte and hoping for the best, Arduino will <em>wait</em> until a minimum of three bytes arrive in the buffer, and then read the first byte to determine whether or not it is, in fact, a header (255).  If it&#8217;s not, Arduino skips that value, and moves on to the next byte without touching the servos.  When it finally sees a header, Arduino continues reading the next two bytes, in order, and assigning them to the Servo Number and the Servo Position, respectively.  If either of <em>those</em> two values is &#8217;255&#8242;, Arduino assumes something is wrong, and skips everything until it reads a new header.</p>

<p><strong>Side Note:  Authoritarian Flow Control</strong></p>

<p>&#8220;Now just a minute!&#8221; you&#8217;re saying.  &#8220;If that is the case, then <em>some</em> of the commands Python sends to the Arduino will be totally ignored!&#8221;  And you&#8217;re right.  This method of serial flow control is definitely one-way, with no error-checking.  Other methods, such as &#8220;call-and-response&#8221; or &#8220;<a href="http://itp.nyu.edu/physcomp/Labs/Serial">handshaking</a>&#8221; are much better at ensuring accuracy, since there&#8217;s a back-and-forth arrangement that can call for data to be re-sent in the event of dropped packets.  But the two-way protocol this method requires is <em>much</em> slower.</p>

<p>We have to make an engineering decision.  In our application, which is more important, accuracy or quick response?  It depends on exactly how you are using the servos, but if you consider say, a joystick-controlled robot or RC vehicle application, then clearly an immediate response and quick visual feedback is preferable to perfect accuracy.  If you command &#8220;turn right&#8221; with a joystick, and your vehicle doesn&#8217;t respond appropriately, you&#8217;ll just instinctively add more right stick input.</p>

<p>Perfect accuracy is not required.</p>

<h4>Writing the Code</h4>

<p>Very briefly, let&#8217;s look at how the above concepts are implemented in both the Python and Arduino software.</p>

<p><strong>Python Implementation</strong></p>

<p>Whenever we call the <code>servo.move()</code> method, the Python script <code>servo.py</code> handles the serial communication details using the <code>pyserial</code> module, and formats the arguments into the data packet outlined above.  The bare-bones version looks like this:</p>

<pre name="code" class="python:nocontrols">
#!/usr/bin/env python

import serial
usbport = '/dev/ttyUSB0'
ser = serial.Serial(usbport, 9600, timeout=1)

def move(servo, angle):
    if (0 <= angle <= 180):
        ser.write(chr(255))
        ser.write(chr(servo))
        ser.write(chr(angle))
    else:
        pass
</pre>

<p><strong>Arduino Implementation</strong></p>

<p>Arduino opens its own serial connection, waits for at least three bytes to fill the buffer, then starts reading:</p>

<pre name="code" class="arduino:nocontrols">
/** MultipleSerialServoControl.pde (bare bones) **/

void setup() {
  // Open the serial connection, 9600 baud
  Serial.begin(9600);
} 

void loop() 
{ 
  // Wait for serial input (min 3 bytes in buffer)
  if (Serial.available() > 2) {
    // Read the first byte
    startbyte = Serial.read();
    // If it's really the startbyte (255) ...
    if (startbyte == 255) {
      // ... then get the next two bytes
      for (i=0;i<2;i++) {
        userInput[i] = Serial.read();
      }
      // First byte = servo to move?
      servo = userInput[0];
      // Second byte = which position?
      pos = userInput[1];
      // Packet error checking and recovery
      if (pos == 255) { servo = 255; }
</pre>

<p>If Arduino gets a complete packet with header, servo, and angle values, it assigns the new position to the appropriate servo.  If the value of <code>servo</code> is not between 1 and 4 (or whatever maximum number of servos you specify), the loop exits without assigning any new values.  That's it!  The Arduino Servo library really makes servo control easy and painless.</p>

<pre name="code" class="arduino:nocontrols:firstline[26]">
      // Assign new position to appropriate servo
      switch (servo) {
        case 1:
          servo1.write(pos);    // move servo1 to 'pos'
          break;
        case 2:
          servo2.write(pos);
          break;
        case 3:
          servo3.write(pos);
          break;
        case 4:
          servo4.write(pos);
          break;
    }
  }
</pre>

<h4>Whew! We're Done.</h4>

<p>Well, if you've made it this far, congratulations: you're totally insane.  I hope the above dissertation helps at least one person better grasp these concepts, since it took me across many web pages and into several late nights to find the answers.  Good luck!</p>

<h4>References</h4>

<ol>
<li>Tom Igoe, <em><a href="http://www.oreilly.com/catalog/9780596510510/">Making Things Talk: Practical Methods for Connecting Physical Objects</a></em></li>
<li>Tom Igoe, "<a href="http://www.tigoe.net/pcomp/serial.shtml">Serial Communication</a>"</li>
<li>Tom Igoe, "<a href="http://www.tigoe.net/pcomp/serialdata.shtml">Interpreting Serial Data</a>"</li>
<li>Society of Robots, "<a href="http://www.societyofrobots.com/actuators_servos.shtml">Actuators and Servos</a>"</li>
<li>ITP Physical Computing, "<a href="http://itp.nyu.edu/physcomp/Labs/Servo">Servo Lab</a>"</li>
<li>ITP Physical Computing, "<a href="http://itp.nyu.edu/physcomp/Labs/Serial">Serial Lab</a>"</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://principialabs.com/arduino-python-4-axis-servo-control/feed/</wfw:commentRss>
		<slash:comments>92</slash:comments>
		</item>
		<item>
		<title>Arduino Serial Servo Control</title>
		<link>http://principialabs.com/arduino-serial-servo-control/</link>
		<comments>http://principialabs.com/arduino-serial-servo-control/#comments</comments>
		<pubDate>Sun, 09 Dec 2007 18:33:24 +0000</pubDate>
		<dc:creator>Brian</dc:creator>
				<category><![CDATA[electronics]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[serial]]></category>
		<category><![CDATA[servo]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://principialabs.com/arduino-serial-servo-control-2/</guid>
		<description><![CDATA[One of the cool features of the Arduino platform is its ability to talk to other electronic devices using standard protocols. The big draw of physical computing, in my opinion, is the power it gives you to affect a limitless range of real-world objects with your PC, rather than just boring old monitors and printers. [...]]]></description>
			<content:encoded><![CDATA[<div class="video">
<embed src="http://blip.tv/play/wkeg4hMA" type="application/x-shockwave-flash" width="380" height="300" allowscriptaccess="always" allowfullscreen="true"></embed>
</div>

<p>One of the cool features of the Arduino platform is its ability to talk to other electronic devices using standard protocols.  The big draw of physical computing, in my opinion, is the power it gives you to affect a limitless range of real-world objects with your PC, rather than just boring old monitors and printers.</p>

<p>This short tutorial will demonstrate one way to use Arduino to control a servo motor with a PC, using a USB cable and the Arduino&#8217;s serial library.  It will in no way attempt to be an introduction to asynchronous serial communication, since such topics are <a href="http://www.tigoe.net/pcomp/serial.shtml">better addressed elsewhere</a>.</p>

<p>RC servos are comprised of a DC motor mechanically linked to a potentiometer. <a href="http://principialabs.com/arduino-pulse-width-modulation">Pulse-width modulation</a> (PWM) signals sent to the servo are translated into position commands by electronics inside the servo. When the servo is commanded to rotate, the DC motor is powered until the potentiometer reaches the value corresponding to the commanded position.</p>

<p><span id="more-41"></span></p>

<p>A standard RC servo has three wires: Ground (black or brown), Power (red) and Control (orange, yellow or white) and will move based on pulses sent over the control wire.  The control pulses set the angle of the servo horn. The servo expects a pulse every 20 ms in order to gain correct information about the angle. The pulse width maps directly to the servo angle.  Most servos will rotate 180&deg;, and expect pulse widths between 1-2 ms or so.</p>

<div style="text-align: center;">
<img src="/files/servo-pwm.jpg" alt="Servo Control with PWM" /><br /><small>Image credit: <a href="http://www.societyofrobots.com/actuators_servos.shtml#control" alt="">Society of Robots</a></small>
</div>

<p>This project uses a <a href="http://www.horizonhobby.com/Products/Default.aspx?ProdID=JSP20050">JR Sport ST47 Standard servo</a>, which accepts an input voltage between 4.8 and 6 volts &#8212; perfect for the Arduino&#8217;s 5V output pin.  Connect the servo&#8217;s brown and red wires to the Arduino&#8217;s Gnd and 5V POWER pins, respectively (colored orange in the diagram below), and connect the servo&#8217;s orange control wire to the Arduino&#8217;s digital pin #2 (on the green row in the diagram).</p>

<div style="text-align: center;">
<img src="/files/arduino_board.png" alt="Arduino Diagram" /><br /><small>Image credit: <a href="http://www.arduino.cc/en/Guide/Board" alt="">Arduino.cc</a></small>
</div>

<p>Using the Arduino IDE, upload the following code to the board, which will allow you to control the position of the servo over a serial connection.  Pay particular attention to the variables <code>minPulse</code> and <code>maxPulse</code>, as these define the min and max pulse widths for your servo.  As mentioned earlier, most servos expect a pulse width between 1-2 ms, however, a range of 0.5 ms to 2.5 ms (500-2500&mu;s) may be required, depending on your servo.  Experiment as necessary.</p>

<pre name="code" class="arduino">
/*
 * NewSerialServo
 * --------------
 * Servo control from the Serial port
 *
 * Alteration of the control interface to use < and > keys
 * to slew the servo horn left and right.  Works best with
 * the Linux/Mac terminal "screen" program.
 *
 * Created 10 December 2007
 * copyleft 2007 Brian D. Wendt
 * http://principialabs.com/
 *
 * Adapted from code by Tom Igoe
 * http://itp.nyu.edu/physcomp/Labs/Servo
 */

/** Adjust these values for your servo and setup, if necessary **/
int servoPin     =  2;    // control pin for servo motor
int minPulse     =  600;  // minimum servo position
int maxPulse     =  2400; // maximum servo position
int turnRate     =  100;  // servo turn rate increment (larger value, faster rate)
int refreshTime  =  20;   // time (ms) between pulses (50Hz)

/** The Arduino will calculate these values for you **/
int centerServo;         // center servo position
int pulseWidth;          // servo pulse width
int moveServo;           // raw user input
long lastPulse   = 0;    // recorded time (ms) of the last pulse


void setup() {
  pinMode(servoPin, OUTPUT);  // Set servo pin as an output pin
  centerServo = maxPulse - ((maxPulse - minPulse)/2);
  pulseWidth = centerServo;   // Give the servo a starting point (or it floats)
  Serial.begin(9600);
  Serial.println("      Arduino Serial Servo Control");
  Serial.println("Press < or > to move, spacebar to center");
  Serial.println();
}

void loop() {
  // wait for serial input
  if (Serial.available() > 0) {
    // read the incoming byte:
    moveServo = Serial.read();

    // ASCII '<' is 44, ASCII '>' is 46 (comma and period, really)
    if (moveServo == 44) { pulseWidth = pulseWidth - turnRate; }
    if (moveServo == 46) { pulseWidth = pulseWidth + turnRate; }
    if (moveServo == 32) { pulseWidth = centerServo; }

    // stop servo pulse at min and max
    if (pulseWidth > maxPulse) { pulseWidth = maxPulse; }
    if (pulseWidth < minPulse) { pulseWidth = minPulse; }

    // print pulseWidth back to the Serial Monitor (uncomment to debug)
    // Serial.print("Pulse Width: ");
    // Serial.print(pulseWidth);
    // Serial.println("us");   // microseconds
  }

  // pulse the servo every 20 ms (refreshTime) with current pulseWidth
  // this will hold the servo's position if unchanged, or move it if changed
  if (millis() - lastPulse >= refreshTime) {
    digitalWrite(servoPin, HIGH);   // start the pulse
    delayMicroseconds(pulseWidth);  // pulse width
    digitalWrite(servoPin, LOW);    // stop the pulse
    lastPulse = millis();           // save the time of the last pulse
  }
}

</pre>

<p>Once you&#8217;ve got the code uploaded, you&#8217;re ready to go!  You can send and receive serial data using the Arudino IDE&#8217;s Serial Monitor, or you can use a Linux terminal (as in the video) with the <code>screen</code> command, like so:</p>

<pre>
screen /dev/ttyUSB0 9600
</pre>

<p>The first element of the <code>screen</code> command specifies the USB port, and the second the serial baud rate (9600).  You may need to run <code>ls /dev/tty*</code> to find the correct USB port on your machine.</p>

<p>The theory behind this project can be extended to include a graphical user interface on the PC to control the servo motor, and maybe even the addition of an Ethernet connection for networked control.</p>

<p><strong>Update:</strong>  (10 Dec 2007)  <em>I wasn&#8217;t happy with the &#8220;Enter Servo Position (0-9):&#8221; interface shown in the video, so I revamped the code to allow left/right movements using the &lt; and > keys.  This new sketch is the one that is currently displayed here.  <a href="http://todbot.com/blog/spookyarduino/">Tod E. Kurt</a> already has a good implementation of the 0-9 angular-position concept if you prefer it.</em></p>

<div class="new"><b>New:</b> <em>Check out the <a href="/arduino-python-4-axis-servo-control/">Arduino-Python 4-Axis Servo Control</a> tutorial</em></div>

<p><strong>References</strong></p>

<ol>
<li>Wikipedia, &#8220;<a href="http://en.wikipedia.org/wiki/Servomechanism">Servomechanism</a>&#8220;</li>
<li>Society of Robots, &#8220;<a href="http://www.societyofrobots.com/actuators_servos.shtml">Actuators and Servos</a>&#8220;</li>
<li>ITP Physical Computing, &#8220;<a href="http://itp.nyu.edu/physcomp/Labs/Servo">Servo Lab</a>&#8220;</li>
<li>ITP Physical Computing, &#8220;<a href="http://itp.nyu.edu/physcomp/Labs/Serial">Serial Lab</a>&#8220;</li>
<li>Tom Igoe, &#8220;<a href="http://www.tigoe.net/pcomp/serial.shtml">Serial Communication</a>&#8220;</li>
<li>Tom Igoe, &#8220;<a href="http://www.tigoe.net/pcomp/serialdata.shtml">More on Serial Communication</a>&#8220;</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://principialabs.com/arduino-serial-servo-control/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
