Category Archives: Robotics

Robotics 2013-12-31

At about 1500L today the insectoid walked for its first time. It took several hours to get there. I started off by spending a while in vain trying to use my board programmer with my Mac with the parallel-to-USB adapter I had recently acquired. No such luck. I thought about just calling it a day with the accomplishment being to order a USB board programmer, but I decided that would be lame, so it was back to the ancient beast of a machine that lacks wireless… After much staring at the micro-controller’s data sheet, tinkering with the components, experimental programming, and furrowing of brow, the machine finally showed signs of life. The first walk was sort of a drunk walk and more than a little disappointing. Several iterations later, both in code and hardware, I had something that I was happy to file under A Good Day’s Work.

It had some traction issues on the tile floor.

The servo controlling the center legs doesn’t seem to have enough power to fully tilt the chassis.

And some combination of calibration issues and traction issues are causing drift to one side in the gait.

Switching to sharper movements will not by itself save the day.  An aerial view illustrates that the legs are not swinging symmetrically.

A little bit of servo calibration later and things are more symmetrical.  This is also using a simultaneous swinging of the leg pairs, with unclear consequences.

Now we’re back to non-simultenous leg movement with no apparent degradation in performance.

Some surround-shots of the action…

And finally I struck on the idea of removing the rubber feet from the center legs to counter the problem of them dragging due to inadequate lift power coming from the servo…

The code is not that complex once you understand the relevant bits of configuring the micro-controller.   The system has one 16-bit timer, one 8-bit timer, and two output channels hung off of each.  See earlier posts for more detail.  One of my main disappointments by the end of the exercise was the realization that if you’re stuck using an 8-bit timer to generate a PWM signal for a servo then even the best possible configuration of pre-scaler and TOP value does not give you much granularity which leaves you with jerky motion as your only option.  I also learned the hard way that the registers used for specifying the TOP value for counters are used constantly, not latched at configuration time, which when you consider that the only way to specify a custom value of TOP for the 8-bit output channels is to put it in one of the output-compare registers, you find that you lose one of your channels which seems a bit miserly to me.

I am relieved that everything seems to work, at least to a degree.  I feel lucky that the micro-controller I chose gave me enough leeway to do what I wanted, if not entirely beautifully.  All these years later I could probably get a much nicer one than I initially bought.  I wonder if more powerful servos would do the trick for the tilting problem.  Or maybe I need to run more power to them because the strain is overloading the batteries and causing a voltage drop?  I suppose I could test this by hooking up to a wall power supply.  In any case, there is still an infinite amount of playing to be done, but today marks a major milestone and is cause for celebration.

[sourcecode language=”cpp”]
#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>

int configure_pwm() {
DDRB = (1 << PB4) | (1 << PB3);
DDRD = (1 << PD5);

OCR0B = 10;
OCR1B = 1500;
OCR1A = 1500;

// 16-bit timer configuration
ICR1 = 20000;
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);

// 8-bit timer configuration
OCR0A = 164;
TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << WGM02) | (1 << CS02) | (1 << CS00);

return 1;
}

int left_pair_forward() {
OCR1B = 1800;
return 1;
}

int left_pair_back() {
OCR1B = 1000;
return 1;
}

int right_pair_forward() {
OCR1A = 1000;
return 1;
}

int right_pair_back() {
OCR1A = 1800;
return 1;
}

int tilt_left() {
OCR0B = 8;
return 1;
}

int tilt_right() {
OCR0B = 12;
return 1;
}

int pause(int duration) {
int i = 0;
for (i = 0; i < duration; ++i) _delay_ms(20);
}

int walk() {
while (1) {
tilt_right();
pause(10);
left_pair_forward();
pause(50);
right_pair_back();
pause(50);
tilt_left();
pause(10);
right_pair_forward();
pause(50);
left_pair_back();
pause(50);
}

return 1;
}

int main(void)
{
int i = 0;
configure_pwm();
walk();
}
[/sourcecode]

Robotics Journal

I just now finished transferring a journal of my robotics work to this here WordPress site to co-habitate with my other blogging activities, backdating the entries accordingly.  It involved a fair amount of work but it’s done and it feels good.

Now I just have to finish the project that I started so long ago.  Going through the transfer process entailed proofing and thus re-reading everything I’ve done.  It is both heartening, seeing all of the obstacles I have surmounted, and dismaying, seeing how bursty my work on the project has been.  Hidden in the gaps are various life events and other distractions that have drawn my attention elsewhere.  The mirrored version of the robotics journal thus far could be a whole other story that remains largely unwritten.  Therein lies a collection of life lessons for me to ponder.

I think with one good day’s work I can have a walking, or at least stumbling, robot brought to life.  But the record shows that I have thought this previously.  Details, details…

Robotics 2013-07-03

Doh! It turns out that all I had to do to make the twitching servo problem go away was to wire a ground pin on the micro-controller board to the common ground for everything else. I thought that I had done the equivalent of this by having the micro-controller board’s power line’s ground going to a common ground, but I guess there is a difference between logical ground and power ground, and without getting them all to the same place the servo did not have a good reference voltage for its signal line (or something).

Of course, I didn’t figure this out without first tearing apart everything, trying to rule out shorts or burned out components, testing things in isolation, even wiring up the signal line to my oscilloscope, etc…

Live and learn… Now I just need to rig up a ribbon cable so that all three servos can be wired up at the same time, then extend the proof-of-concept code to operate all three legs in concert, and we’ll have a walking robot…

Robotics 2013-06-22

Bangs. Head. On. Desk.

Given that there was already a perfectly good program on the micro-controller for swinging a leg pair, I tried one-by-one wiring up the signal line for each servo in the hopes of validating that all the wiring was good, and… twitching. The damned servos are twitching.

Maybe the way I ran the wires is causing interference? Maybe it’s a load issue? Maybe the servos are busted or the micro-controller board has started having issues? Various Internet posts say to try putting a resistor in series with the servo, or maybe wrapping its cabling around a torus…

Argh! This is going to be a bit of debugging…

Robotics 2013-06-16

So close to having a walking robot that I can taste it… Today was equal parts assembly work and data sheet perusing.

The UPS man had dropped off a couple of 9V battery holders earlier in the week, one of which I mounted to the chassis after some soldering work. I also changed out the wiring to the DC plug I have such that the power for the micro-controller can be run to the breadboard as opposed to being directly tied to the battery (decoupling, FTW). Then I ran an assortment of wires and jumpers to power everything…

everything_mounted_and_powered

Perhaps after the next session the creation will rise and walk the earth…

I did a little digging in the micro-controller’s specs to figure out what my options are for driving all three leg pairs. It looks like pins PB2-PB4 double respectively as OC0A, OC1A, and OC1B. So, I’ll need to do some ribbon-cable magic to finish up today’s wiring exercise to get those pins linked up to the signal ports of all the servos. I figure I will use the two 16-bit timers for the side leg pairs and one of the 8-bit timers for the tilter leg pair.

Some maths have me reasonably convinced that I can make an 8-bit timer work for my purposes. A pre-scaler value of 1024 gets us to 8192 counter ticks per second. For a 50Hz signal, that means setting the roll-over for the counter (the “TOP” value) to 164. One tenth of that, ~16, is a 2ms wide pulse, and half that is ~8/1ms.

Right? We’ll find out soon…

Robotics 2013-06-08

Alright, here we go:

  • Acquire a miniature breadboard: check
  • Cut, drill, and mount another aluminum sheet to serve as additional platform space: check
  • Use double-sided tape to mount breadboard and 4-pack double-A battery holder to platform: check
  • Rig up wiring from servos to breadboard: check

Voila:

bread_board_mounted_top_view

bread_board_mounted_side_view

Remaining tasks in the home stretch to walking:

  • acquire and rig up a 9V battery holder for powering the micro-controller board
  • wire up all the necessary power and data lines to and from the breadboard
  • build out from prototype leg-controller code to drive all three leg pairs in concert

We’re almost there.

Robotics 2013-04-21

So, somehow all of this electro-mechanical jumble needs to get hooked together in a way that won’t tangle or tether. As it stands, there is no good place on the chassis to directly mount the microcontroller’s board, so we’ll need to concoct some sort of platform…

staged_board

… that can rest on top of a section of aluminum tubing that elevates it adequately…

mounted_board_rear_view

The key thing in the assembly of this apparatus was appreciating the value in a component that did not so much add structural function to the final product but rather served to make assembly far easier, specifically the lock nut that went directly beneath the platform. This nut both reduced the freedom of a sub-assembly to wobble during final assembly as well as provided a handy surface with which to execute the final assembly. The alternatives, which included trying to screw down the board as the last step or trying to run the platform-mounting screw upward instead of downward, were going to be hopelessly fiddly, a seemingly impossible task for a mere two hands.

mounted_board_top_view

In hindsight, I wish I had cut the sheet of aluminum that serves as the platform floor to be the length of the chassis so as to create more real estate to mount the rest of the components, namely a breadboard (of a miniature nature that I need to acquire) to plug everything together and a couple of battery packs to power everything. I’m debating whether I ought re-cut this piece larger and mount it at both ends of the chassis or just cut another smaller piece and tell my OCD that everything will be just fine.

Robotics 2012-12-09

And now for something closer to the real deal, using one of the AVR’s timers to implement and steer a Pulse Width Modulated signal that swings one of the robot’s leg pairs gently backward and forward…



#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>

int sleep() {
  int i = 0;

  for (i = 0; i < 2; ++i)
    _delay_ms(10);

  return 1;
}

int main(void)
{
  int i = 0;

  DDRB = (1 << PB4); // configure port PB4 as an output port
  ICR1 = 20000;      // place the desired TOP value in the register whence it will be sourced
  OCR1B = 1500;      // set the initial width of the pulse

  // tell the micro-controller the wave generation mode of interest, the pre-scaler, and how to output the signal
  TCCR1A = (1<<COM1A1)| (1<<COM1B1) | (1<<WGM11);
  TCCR1B = (1<<WGM13) | (1<<WGM12)  | (1<<CS11);

  while (1) {
    // gradually widen the pulse
    while (OCR1B < 1800) {
      OCR1B += 10;
      sleep();
    }

    // gradually narrow the pulse
    while (OCR1B > 1200) {
      OCR1B -= 10;
      sleep();
    }
  }
}
    

In other words, we want the servo to be given a PWM signal with a frequency of 50Hz, so we match a pre-scaler of 8 with our 8MHz processor to yield 1M ticks per second, we carve those million ticks up into chunks of 20K ticks to yield a 50Hz signal, and we invert the output signal from high to low somewhere between 1200 and 1800 ticks into a chunk to yield a pulse width between 1.2ms and 1.8ms… Voila!

Now we just have to control all three leg pairs, do it in concert, and somehow hook everything together so when the robot actually moves it doesn’t unplug itself…

Robotics 2012-12-01

Servos gotta move… That’s how this robot is gonna walk… This entails sending them a Pulse Width Modulated (PWM) signal… Essentially this means sending sending a pulse train to the servos for which the signal is high for a certain fraction of the time and doing so with a certain frequency, thus effecting a certain duty cycle…

It’s possible to take the reins and do this yourself, writing code that flips the value of an output port back and forth repeatedly to bring about the desired effect…


#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>

int neutral() {
  int i = 0;

  for (i = 0; i < 100; ++i)
    _delay_us(15);

  return 1;
}

int skew() {
  int i = 0;

  for (i = 0; i < 100; ++i)
    _delay_us(20);

  return 1;
}

int main(void)
{
  int i, j;

  // Set Port B pins as all outputs
  DDRB = 0xff;

  while (1) {
    for (i = 0; i < 60; ++i) {
      // Set all Port B pins as LOW
      PORTB = 0;

      for (j = 0; j < 10; ++j)
        neutral();

      // Set all Port B pins as HIGH
      PORTB = 0xff;

      neutral();
    }

    for (i = 0; i < 60; ++i) {
      // Set all Port B pins as LOW
      PORTB = 0;

      for (j = 0; j < 10; ++j)
        skew();

      // Set all Port B pins as HIGH
      PORTB = 0xff;

      skew();
    }
  }

  return 0;
}
    

Hook a servo up to this signal and it will swing back and forth periodically. That said, it’s tedious so have your main body of code encumbered thusly, as there are likely other things you want your robot’s micro-controller to be pondering.

Enter the micro-controller’s timer faculties… The ATtiny2313 supports two 16-bit timers and two 8-bit timers. In this context, a timer is a register that gets its value incremented after a particular unit of time. This increment operation can occur either every tick of the clock, or after every N ticks, N defining a so-called “pre-scaler”. These timers also support Pulse Width Modulation by virtue (when operating in certain modes) of having the timer not roll over to zero when it reaches its maximum value (at which point it invokes an interrupt routine) but rather start counting down, and upon reaching zero start counting up, and at the endpoints inverting the value being sent out on a configured port.

The key components of configuring such a setup are setting the “TOP” value for the counter, setting a pre-scaler value for it, and telling the micro-controller to operate the given timer in a specific PWM mode. With some help from an AVR Freaks forum entry and the ATtiny2313 data sheet I was able to puzzle through creating a basic program to test out these faculties, and by wiring up an LED to a breadboard get visual confirmation that things were working as expected.


#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>

int sleep() {
  int i = 0;

  for (i = 0; i < 10; ++i)
    _delay_ms(10);

  return 1;
}

int main(void)
{
  int i = 0;

  // configure port PB4 as an output port
  DDRB = (1 << PB4);

  // place the desired TOP value in a register whence it will be sourced
  ICR1 = 10000;

  // set the initial width of the pulse
  OCR1B = 0;

  // tell the micro-controller the wave generation mode of interest,
  // the pre-scaler, and how to output the signal
  TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
  TCCR1B = (1<<WGM13)|(1<<WGM12)|(1<<CS11);

  // and then gradually dial the duty cycle up and down...
  while (1) {
    for (i = 0; i <= 10; ++i) {
      OCR1B = 1000 * i;
      sleep();
    }

    for (i = 20; i >= 0; --i) {
      OCR1B = 1000 * i;
      sleep();
    }
  }
}
    

If you hook up an LED to the PB4 port, you will see it fade in and out in response to the duty cycle being dialed up and down. Such behavior is a stepping stone to driving a servo. In the case of the servo, a desired frequency of 50Hz means a period of 20ms, which means setting “TOP” to 20000 (given an 8MHz processor speed and a pre-scaler value of 8), and then we can make the servo deviate from the neutral position (with a 1.5ms pulse width) by ranging the value in OCR1B between 1000 and 2000.

At least that’s the theory… We’ll see how it goes when we switch from an LED to a servo. I’m also a little worried that although the ATtiny2313 micro-controller boasts 4 PWM channels it seems that two of them are underpinned by a 16-bit timer but the other two are underpinned by an 8-bit timer. The robot has three servos, meaning that they can’t all be running on 16-bit timer driven PWM outputs, and so I am hoping that somehow the right pre-scaler value applied to an 8-bit timer will give a good enough resolution. I haven’t yet thought this all the way through…

Robotics 2012-11-25

25 November 2012

Alright, so years ago I purchased a micro-controller to make this robot dance, an Atmel ATtiny2313, and I figured out how to program some “hello, world” style applications for it, to include making an LED blink and an attached servo swing back and forth, but time passed, and this knowledge grew faint, and meanwhile some of the parts broke in transport. Today’s exercise was to dust off the relevant cobwebs, physical and mental. Being a practical sort of guy, I originally bought not just a stand-alone micro-controller, but rather a board with the related infrastructure to power it and wire up devices to its ports…

unwired_board

… because a guy can only learn so many things at the same time, and first up was powering the thing, which entails getting somewhere between seven and twelve volts of direct current going into it, a contraption such as the following being required…

finished_soldering_plug

… which looks simple enough, except that the 9V battery hookup and the DC plug come as separate contraptions that need to be soldered together…

soldering_plug

… which entailed evicting the dog from one of his favorite spots…

dog_eating_yogurt

… so that we could eventually end up with the following rig…

testing_wired_up_board

The principal reason that I chose an Atmel micro-controller was the ability to program it with a Linux-based tool chain that used the C programming language, as opposed to the more popular PIC micro-controller for which Windows and Basic (*vomit in mouth*) seem to be required.

Meanwhile, the program transfer mechanism I received uses a printer cable, and I didn’t have a printer-cable-to-USB adapter handy, which left me in the position of using an ancient laptop I had sitting around running Ubuntu, for which I was able to apt-get the packages gcc-avr, avr-libc, and avrdude, and then build programs with…

  • avr-gcc -mmcu=attiny2313 -Os -o <program_name>.out <program_name>.c
  • avr-objcopy -j .text -O ihex <program_name>.out <program_name>.hex
  • avrdude -c pony-stk200 -p t2313 -e -U flash:w:/path/to/<program_name>.hex

… incantations I was able to invoke as quasi-magic because former-Andrew was a swell guy and actually documented the stuff he did years ago and uploaded it to GitHub. Less well documented was the plug via which the programming cable needed to be attached, but fortunately I had the good fortune to have documented this by not unplugging the constituent pieces, the arrangement of which has now been documented in photographic form. Even less well documented was the fact that after running avrdude to install a program the commencement of its execution requires unplugging the programming cable, but somehow I remembered this years later. A good memory has some advantages…


/* blink the LED on the board */
#include <avr/io.h>
#define F_CPU 8000000
#include <util/delay.h>

int sleep() {
  int i = 0;

  for (i = 0; i < 100; ++i)
    _delay_ms(10);

  return 1;
}

int main(void)
{
  // Set Port D pins as all outputs
  DDRD = 0xff;

  while (1) {
    // Set all Port D pins as LOW
    PORTD = 0;

    sleep();

    // Set all Port D pins as HIGH
    PORTD = 0xff;

    sleep();
  }

  return 0;
}
    

Now I need to write the code to coordinate the activation of the three servos and somehow wire up and bolt together the requisite electronic and mechanical infrastructure… The code is what it is… The mechanical and electrical stuff can be resolved somewhat more incrementally, first with a breadboard that can be hand-held as I “chase” after the robot, and then later with something more permanent to render the robot more autonomous… Baby steps…