Let's Make Robots!

simple ardbot

simple Arduino robot test platform

 

My first non-kit robot. Inspired a lot by the "Start here" robot on this site!

Not much happening yet. I put together my motor shield, and tested it by moving a couple motors and a couple  servos simultaneously. Next I stuck the wires to one sharp distance sensor through convenient analog/power sensor holes on the motor shield and started testing. I sent the output to the serial to get a look at it, then added a servo and wrote some code to turn the servo based on the distance reading. I discovered an interesting thing though - I had some mystery jitter in the sensor readings (evidenced by the twitchy servo)!

 Now the variability of the sensor readings and the smooth motion of the servo probably have no bearing on the functioning of my final robot. It seemed like such a fun and simple thing to hack around with though, I just had to do something about it. I figured I would just filter the sensor signal so the movment wouldn't be so jumpy, and I already knew a nice filter function for noisy time series data called a weighted moving average. Specifically I used exponential weighting, since that was more tunable. For testing I wrote a little Python script using the matplotlib and numpy modules to get the smoothing function working. At first I just added some noise to a scaled sine wave as fake data, but later I copied the Arduino's serial output to a file. Here is the output of the tuned algorithm on saved sensor data:

graph

graph_zoom

The time offset is just bearly noticable at ~ 1/10 of a second. Here is my averaging function (which hopefully wont get mangled):


def ewma(data, fac=0.5, width=5):
    """Calculate the exponentially weighted moving average of the data points."""
    window = deque(list(), width) # cut off old data
    facs = [fac**(i+1) for i in range(width)] # factors are constant
    results = list()
    for datum in data:
        window.append(datum) # Extra data falls out other end of window
        avrg = sum([window[i]*facs[i] for i in range(len(window))])/sum(facs[:len(window)])
        results.append(avrg)
    return results

With that non-sense running successfully on my Arduino I started laying out my bot on Sintra.

partslayout

 


Continuing:

 

I finished building the chassis about a week ago, but got caught up in a big project at work... I sort-of remember what I did - all the pictures help!

 So first I tried to build some motor mounts by bending Sintra - which didn't work at all! The water was really boiling, and I left the pieces in for quite a while, but when I took them out to bend they were still somewhat stiff - and they cooled so quickly I couldn't shape them! (As a side note, I got a sample of ShapeLock during the week. It is definably as cool as it is made out to be!)

Cutting the brackets to be bentcut out brackets

My second attempt was to cut and superglue the pieces into shape. This might have worked out, but the pieces weren't designed for it. I ended up loosing too much material in the cuts. Also I wasn't careful enough smoothing and matching the cuts, so joining them was difficult and nothing was square. Also I didn't allow clearance for the motor shaft.

Failed bracketFailed bracket

Finally I decided to go for something simpler. I grabed an old scrap disk drive and managed to pull a nice thin sheet of aluminum off it. I was still a little sloppy with my measurements, but these brackets got the job done!

New bracketsNew bracketsNew brackets

From there mounting the motors was easy. I made a mistake cutting the slots for the first motor though, so I had to add a wedge.

Mounted motorMounted motor

Next I mounted the sensors, this time with little Sintra brackets superglued to the platform.

Sensor bracketSensor bracketSensor bracket

Looking pretty good! Next I cut a hole to mount a servo. I intended to create a single servo gripper mechanism, but I've changed my plans since.

Servo mountServo mount

You can see I also added a sort of 'firewall' looking thing to help hold the batteries in place. I also cut a square of Sintra to mount the Arduino to. poof -> finished robot!

Finished frontFinished back

 Programming went pretty well. I just mapped the distance readings from each sensor to the power output of the motor on the opposite side. This means that as it approaches an object off to the left it will put less and less power to the right motor (as the distance decreases) while the left motor continues at something closer to full speed. The mapping is linear, but with some built-in thresholds to ensure the 'bot doesn't stall, and keeps moving with max readings (which vibrate erratically around 130cm).

This performed fairly well, except there is an odd quirk to these sensors. The sensors are meant to operate at distances from 10cm to +80cm, but at distances below 10cm the sensor readings start increasing again! This meant that an object 40cm away looked the same as an object practically touching the sensor! Also there was no way to differentiate between the bad readings and for instance a wall sloping away from the robot...

The behavior resulting from the bad data was a little interesting though - The robot would slow as it approached an obstacle face on until the 10cm threshold was passed, at which point it would accelerate into the obstacle in a seemingly aggressive manner! It was pretty entertaining, and could be useful for overcoming light or flimsy obstacles, so I didn't want to change that behavior. After the show though the robot would just sit pushing against the object with its motors stalled.

I came up with a simple solution that seems to work well: I have a function called "am_stuck" which compares the current sensor readings with the previous readings. If both sides are the same it pushes true onto the right side of a big boolean array, otherwise false. It also checks if all the values in the array are true (by ORing to a the current value), in which case the robot is stuck. The mainloop then just checks if am_stuck() and if so runs a little back and turn routine. I was thinking I could just use a byte or something to store the sameness array, but because the reading happen so quickly the array needed to be fairly large (~100 items?). With fewer items the robot just thinks its stuck all the time, and traces nice little squares on the floor!

 Anyway, I've decided I'm not interested in a gripper. Especially when I realized how few things it could grip. I've decided instead to mount each IR sensor on a servo so it can make better decisions when and if it is stuck. I've also got some light sensors, temp sensors, and touch switches, so I was thinking about adding more senses and behaviors to it. I plan to start work on a quadruped soon though, so I don't know how much attention this guy will get...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

 

Lol, I was thinking about something else this morning when all at once I thought of a much simpler and direct way to implement the am_stuck function! It is embarrassingly obvious too. I was stuck on the idea of using a queue of bools, and when the execution speed turned out to be so quick I just made the queue bigger. Really all I needed was an accumulator, probably an int, and a threshold that if (counter > threshold) reset counter and call the back and turn function! I could probably drop a couple of variables, and tens of lines of code...

Oh well, just an early morning revelation. I'm actually working on a 4dof robotic arm right now to use for IK/FK testing. I'll post something once I get beyond the 'pile of sticks and servos' stage.

Now, I'm not sure if this is possible with the sharp sensors, but I know for a fact that sonar (SRF005) can pick up fuzzy carpet if mounted too low. --can lead to false readings. I would be surprised if your sharps are doing this but you never know.

Thanks!

Yeah, I heard about the cross-fire trick before, but once I started building I got too caught up in figuring out how to stick things together. I guess I was thinking more about the form than the function.

For Sintra, I think your right. It is a PVC based foam used mostly for sign making? <Wikipedia>

 The related blog post at the top has a list of materials linked to the components section of this site too.

 

One other funny bit of behavior I noticed with this 'bot -  it doesn't like carpet. I tried it at work where they have a pretty tight knap and it can struggle along at a diminished pace, but at home we have normal fluffy carpet. When it steers off the linoleum unto the carpet it bogs down quite a bit. After a few seconds of trying to crawl through though it changes its mind, turns around, and makes a bee line for the smooth floor!

It has to do with the am_stuck routine of course. The slowed movement means the sensor values don't changemuch, which indicates am_stuck! Pretty good for only two sensors and no motor encoders!

 

Ed

Awesome:

Loved the experimentation on the servo jitter

Loved the nice break-job on folding up the motor mounts --there is just no good way of mounting those things

I think you used the same stuff I used for Walter --EPVC OR CPVC, right? You call it sintra, mine is Azek. Plastic exterior trim for houses.

Just a good looking, clean bot

 

Only one suggestion: I have found that those sharps seem to work a lot better in a cross-fire set-up. The one on the left fires at a 45 deg. to the right and vice versa. You loose that center-line hole. 

Good stuff.