- DIY
- A
Entertainment for an engineer
I've always been interested in playing with a programmable robot, but there were neither resources nor desire to study circuit design. So, when I came across a robot quadruped assembly kit, I bought it immediately. All the hardware in it was already made.
Sometimes, some free experiments in a certain field can bring unexpected and amusing results. I never could have predicted that I’d end up with a cat, especially a dancing one.
Crawling Robot
Assembly of the kit took just over an hour, and the way to experimentation was open.
The little guy turned out to be quite funny. The demo program delighted not only my wife, the kids, the cats, but also me. The kit included a visual programming app, a la Scratch, which could be used to make it walk, turn, tilt, and do all sorts of other things.
Once, by accident, I straightened the quad’s legs and turned its belly towards me. The rangefinder eyes completed the picture – it turned into a humanoid robot. There was no going back.
Upright Robot
The solution for the feet came a couple of days later. I wanted to make a modification that was both non-destructive and easy to take apart. I decided to use elements of a tile leveling system right away. The only issue was figuring out how. The legs are cone-shaped – every attempt to wedge them in failed, it was unreliable and they kept popping out. In the end, I took advantage of the fact they’re hollow – I drilled holes in the sides of the tile levelers and fed a regular paperclip through them and through the leg itself, twisting the ends.
The quadruped evolved into an upright-walking robot – it could confidently stand on its own legs.
Evolving Robot
I’d never dealt with Arduino before, so I chose the “simple” route: take a look at how things were done in the block app and try to replicate it.
It turned out to be possible – the app ran on Electron with open js files. After digging around, I roughly figured out how to control the servos, which was enough to get started. I didn’t even have to dig inside the app – it had a button that shows the generated code. Later on I did have to look at the manual to figure out how to send data to the port in order to get an analog of console.log.
At first, I wanted to teach the robot to walk. Reality made its own adjustments. It’s not easy to achieve accurate and stable forward movement with two servos per leg. Getting a precise turn is, frankly, tough. The tile levelers couldn’t help there. That was starting to go beyond just having fun.
Watching the kids have fun dancing along with Just Dance, I thought – maybe I should teach the robot to dance?
Dancing Robot
So, a dance. Movements in time with the music. Let’s begin.
First, you have to get the timing right. To stay in rhythm, you need to move the limbs at the right speed. The VarSpeedServo
library is used to control the servos, which lets you specify both angle and speed. However, speed here is an abstract value. You have to tie it to some concrete measure.
Through experimentation, I identified a constant, which I named anglePerSecondPerSpeedUnit
– the angle by which the servo’s position changes per unit of abstract speed per second.
After roughly planning how I’d describe the movements, I realized I needed a function that moves the servo through a specific angle in a set number of milliseconds.
Later, I modified the interface for more convenience – the function now takes the target position as a parameter – where the servo should end up. It figures out the difference from the current position and moves the servo where it needs to be in the allotted time. When you’re programming a dance, you don’t want to think about where the arm, shoulder, or shin used to be – you want to specify where they should get to and in how much time.
void _moveByTime(int index, int a, int timeMs) {
int diff = a * _getDirection(index);
int newAngle = _init[index] + diff;
int length = abs(_state[index] - newAngle);
int absSpeed = length * 1000 / timeMs;
int speed = absSpeed / _anglePerSecondPerSpeedUnit;
VarSpeedServo servo = _getServo(index);
servo.slowmove(newAngle, speed > 255 ? 255 : speed);
_state[index] = newAngle;
}
The code is primitive – what could possibly go wrong here? But sure enough, I ran into debugging right away. For small angles, the function worked perfectly, but for large angles the servo would twitch unpredictably. At first, I thought the real speed depended on the parameter non-linearly. However, a couple of tests showed that wasn't the case.
I found the solution after an hour. And you know what I’ll tell you…
My main working tool is Typescript, but that’s something else entirely. When you've spent years programming in high-level languages, you forget how many layers of abstraction lie beneath them, and what’s going on all the way at the bottom.
The only thing separating working code from broken was (long)
:
int absSpeed = (long)length * 1000 / timeMs;
I'll just add a story about Linus Torvalds, a genie, and three wishes.
The next surprise was the bar duration of the chosen musical piece. I picked it out experimentally – timing a large number of bars with a stopwatch. Then I fine-tuned it, checking that simple moves match the music. The result surprised me.
Normally, tempo is indicated by a familiar absolute integer – beats per minute, bpm. Likewise, in sheet music, the quarter note (1/4 of a bar in 4/4 time) is specified the same way. Measuring over a large interval, the bar length in this piece in the Just Dance version was 1020 milliseconds. If you count bars, that’s 58.82 bars per minute, if you count quarter notes – 235.29 bpm. These figures defy common sense. Average synthesizers can’t even produce a tempo that precise.
But. Let’s divide 1020 by quarters. A quarter bar in this piece, in the Just Dance interpretation, is 255 milliseconds. In the original track, the bar lasts a bit differently. The Ubisoft developers put in a funny Easter egg.
Breaking down the dance into movements and programming the robot was a routine technical task. I just want to point out that teaching a person (myself or someone else) the necessary movements is much easier than teaching a mechanism. When a person feels the rhythm, most of the work is done by themselves—you just need to show them. A mechanism requires extremely precise instructions about when to start the movement and how long it should take to complete.
I decided not to try to make the robot balance itself and went the simple way: half a meter of VVG 2x6 wire and a clamp solved the stability issue.
Robot Cat
The idea to give the robot an appealing appearance was obvious. The stabilizer immediately became the tail, and from there the options were pretty limited—the cat theme dominates not only with the younger generation but also the older one.
After experimenting with strips of paper, it became clear that with this construction of joints, you need a large margin of fabric on the outer side of the bend. The inner side, on the contrary, will gather into folds. The extra margin can be dealt with, but folds might interfere with the mechanism itself. Stretchy fabric seemed like a good idea at first. However, it didn’t make it to practice: the thought that it would stretch over the joints and make the cat look angular was off-putting.
My wife came up with the solution, saying—“Let me knit it!” And yes, this option was perfect: thick yarn wouldn’t let the frame show through, and at the same time, knitted fabric can stretch and compress well.
Of course, I couldn’t stay aside. The crooked felt boots for legs and the claw-like arms are my work.
Two holes were found in the red frame base, which turned out to be convenient for attaching a plastic corner that would hold the head.
Next, the belly had to be stuffed and all parts crocheted into a single structure. This didn’t cause any difficulties.
I made the whiskers by stripping twisted pair cable. My wife also helped me with the painting, based on one of our house cats, and with a few finishing touches.
This is how the creature turned out:
Hooray! Everything is ready.
But no.
As often happens, adding a complicated new feature led to an old one not working anymore.
Catrobot
The catrobot turned out great, but its dancing left a lot to be desired. At various points, a reboot would suddenly occur: the limbs would jerk sharply and the catrobot would return to its initial state. This could happen either towards the end of the dance, or right at the start.
After debugging, it became clear that the cause of this behavior was the limited mobility of the limbs, which were now surrounded by knitted fabric.
The idea of knitted skin fully paid off—the skin stretches, doesn’t have bubbles, doesn’t gather into creases, and angular parts don’t show through. But it is thick, and in the extreme positions it interfered with movement. I didn’t account for this at first.
The second issue that had to be resolved post-factum was the density of the binding of parts to each other. This did not concern the arms, but the legs were bound in such a way that the robot could not only not do the splits, but even small leg movements in any direction were difficult for it.
Both issues were solved programmatically: I reduced the angles of limb deviations at which excessive force appeared. The randomness of the time when the reboot occurred may be explained by the battery charge level: when it's fresh, the servo has enough energy to either push through or survive a difficult moment, but when the battery voltage drops, a reset occurs in these situations.
Field tests also revealed that the knitted fabric does not slide well on rough surfaces. Leg movement, given the current configuration, is sliding. On surfaces where this is poor, the robot's leg movements are very limited.
In general, although not perfect, the result was achieved. It's time to evaluate the reported dance.
What's next
There is an idea about teaching children programming. Currently, it is often represented by tasks on controlling a robot on a screen. If the robot that moves is not drawn, but real, it will be much more interesting. Interactivity attracts. Moreover, with a real robot, the range of tasks can be much wider. One can create a design that allows incorporating a competitive aspect into the learning process. This is a powerful motivator that works not only for children.
There is an idea for a dancing robot that could dance to any track. Technically, "listening" to music, detecting peaks in low frequencies, selecting movements from a prepared set, adjusting speed – this is possible. Such a robot could not only decorate a children's party but also an adult one.
Circuit design and mechanics are vast areas. To properly implement any of these ideas, one must dive deeply into them. My main qualification and area of interest is the software part. It's unlikely that there will ever be time to fully dive into a new field. But if you decide to implement one of these ideas, I would be happy to either help or take on the entire code myself.
Write comment