Lego Mindstorms cuckoo clock

Two and a half years ago, I bought a set of Lego Mindstorms EV3 to take my first steps in robotics. Having rolled in an ev3dev assembly to the controller and having played enough with the management of engines and sensors over SSH, I cooled for two years to purchase. The reason was that I lacked imagination in terms of what this could be collected: after several assembled models from Lego Technics (both boxed and self-made), I was already used to wonders like remote-controlled toys, and simple robots like the models from Lego presented at the Krakow exhibition, as a person who had worked on the telemechanics system at one time, did not cause enough inspiration. I also didn’t really want to repeat the experience of others.

In the end, it dawned on me: a model with a rather complex, interesting, practical and not too hackneyed clock could become a cuckoo clock. Inspired by this idea, I got down to business.

According to my idea, the model was supposed to be not just a toy, but a full-featured device. This was fully achieved: the clock is hanging on my wall and 24/7 displays the current time. I did not set myself the task of reproducing the mechanism of the original in all details - so, my arrows are independent, the sound is played through the speaker of the controller, and the weights and the pendulum serve exclusively for the surroundings. Having thus shifted all the main work to the program part, I assembled the mechanism in the simplest possible version. I have not documented the entire assembly process, so I will not be able to assemble the model again in the same form; nevertheless, the basic principles of coupling software and mechanics are such that the program should work with minimal modifications on other models assembled according to a similar principle.

Watches in various forms are presented in a video that I posted on Youtube:

Basic information about the model is presented in the video. Below I will talk in a little more detail about the mechanics, the software, as well as the problems that have arisen during the assembly and operation of this design.


The assembly of the mechanical part took 6 days. Having laid out the boxes with Lego on the table, during the New Year holidays I assembled a mechanism that differs from the final version only in the doors behind which the cuckoo lives (more on this below). I don’t have any special design skills, so the watch is a rectangular box with two hands and a dial with dots on the front side. At the top of the clock is a compartment closed by two doors, in which the cuckoo settled, and at the bottom is a sketchy pendulum and two weights. Details were taken from several Lego sets: one Lego Mindstorms EV3 (31313) , two Volvo graders (42030) , one Mercedes pneumatic boom truck (42043) and one truck crane (42009). Despite the abundance of sets, a model of this size was barely enough - the watch cover is assembled from strips of different colors, which, however, does not catch the eye, since it is above eye level with wall mounting.

A standard 15-unit Lego Technics bar is used as a minute hand. It is located on the axis that rigidly connects it with the engine. Thus, the accuracy of setting the minute hand turned out to be sufficient so that it could be used to determine the time to the minute. Hour hand is shorter and fixed on the swivel mechanism. It is connected with the engine through a few gears, so there is quite a noticeable backlash here - however, it is not so big as to cause problems with the definition of time.

The arrows are driven by two large motors (LM). In addition, another one works in conjunction with each of the external hands, the internal one - for the minute hand, it is fixed on the same axis as the first one, and for the clockwork swivel mechanism is duplicated on the inside of the watch. The purpose of the internal arrows is to press the button (Touch sensor) while passing the external arrows through the upper position. Thus, the controller has the ability to determine in which position the arrows are located immediately after switching on, and set them in the correct position based on the system time, saving the user from having to sum up the arrows manually.

Weights are purely decorative function. Initially, I thought to do with one weight, which will slowly descend (as in normal hours), and then quickly pull up to the top position (analogous to the manual winding of the pendulum clock). I subsequently refused this option for several reasons. Firstly, the mechanism for switching gear ratios between the engine and the weight introduced extra complexity into the model (and the drive of the pendulum from the same engine only increased it). Secondly, fast liner, whatever one may say, would be a noisy operation, and I wanted the clock to work as quietly as possible. Thirdly, in the usual cuckoo clock there are usually two weights (one ensures the clock’s course, the second the cuckoo’s work), and placing two changeover wheels for the chain at the bottom of the clock would lead to an even greater increase in the model size.

Proceeding from this, I went in a simpler way: I actually set two weights on the watch, but placed them on a common chain, thrown over the only drive wheel. In this embodiment, the weights are always moving in the opposite directions, dropping in turn. This behavior has little to do with the real pendulum clock, but it looks quite interesting.

The chain is made of ordinary slats of three units using alternating axes and caps: a slipping cap is a rather rare detail, and I used axes to double the length of the resulting chain. It was not so easy to make a wheel that moves such a chain without slippage and breakdowns, but in the end this was also possible.

As for switching the direction of movement of the weights, my first idea was to make it purely mechanical: when climbing to the bottom wall of the watch case, the wide axis, installed directly above the weight, presses the plate through which the chain is threaded and causes the switching of the direction of rotation of the wheel. The switching element I was going to use is the same as, for example, at the crane 42009 : the driving wheel, moving, engages in the grip, then with the right, then with the left neighbor. This idea, however, did not fly: the pressure plate brought the sliding part into a central position, when it was not linked to either the right or left neighbor, the torque ceased to flow to the wheel, and the switch froze in the central position.

To correct this situation, I decided to add to this scheme a moving triangle, the two sides of which would have a fixed length, and the third would be represented by a spring-loaded sliding part used in the suspension of the same truck crane. The meaning of this construction was that the triangle is always on the side of that pressure plate that corresponds to the rising weight: when the weight reaches the top, the panel presses on the triangle, the spring contracts, the triangle passes through the equilibrium position and then "flips" on the other side, releasing spring stored energy. This energy, according to my design, should have shifted the speed switch through the equilibrium position, immediately shifting it to the opposite position.

However, I failed to stabilize this system. By the size of the clock, it can be understood that the miniature mechanisms are not my fad, and as the size of the knot grows, the distortions in it lead to friction, which eats up most of the switching energy. Having worn out with this mechanism, I finally decided to shift all the dirty work to the microcontroller by installing the touch panels on the button (Touch sensor) instead of complicated mechanics.

A little simple arithmetic. EV3 has four inputs and four outputs. Two entrances and two exits were already occupied by buttons and arrows engines, respectively. Adding to this scheme a motor that rotates the wheel of the chain and two buttons meant that, firstly, I didn’t have any ports left to connect the cuckoo's position sensor (I thought to use an optical distance meter for this purpose), and secondly - that the remaining nodes (cuckoo and pendulum) have only one engine. I considered the option when both pressure panels above the weights would be connected to a common button, but refused it, because if one of the weights were in the upper position when the clock was turned on, holding the button, the clock would not have enough information to choose the direction of movement of the chain.

Since the pendulum was easier to associate with the mechanism of movement of the chain than with the cuckoo (both in the nature of movement and location), I placed another large motor in the lower part of the body, which, first, drives the pendulum back and forth (1 engine turn translates into one complete oscillation of the pendulum), and secondly - through a reduction gear rotates the wheel, which drives the chain. Such a system has the disadvantage that when the direction of movement of the chain is reversed and, consequently, the motor rotates, the pendulum also changes directions of movement, even if it is in an intermediate position, which may look ugly. However, switching the direction of movement of weights is a rather rare operation, so I neglected this problem. Another disadvantage of my assembly is rather replacing the backlash in the pendulum drive, which is why, with its slow movement, the pendulum stops for a fraction of a second noticeable to the eye at the lowest point. I was too lazy to fix this problem.

Speaking of the speed of the pendulum. Having experimented with it, I chose a value of 30 degrees engine per second. This means that the pendulum makes a full swing in 12 seconds. This is a lot, but as the speed increases, the engine starts to howl, but I’m not at all smiling at the prospect of continuously listening to his song. Again, I was too lazy to sort out the mechanism and introduce a transmission, so I stopped at such a "lunar" format. The gear ratios between the engine and the chain drive wheel are such that the weight goes from the bottom to the top position in 40-50 minutes.

The port of EV3, which remained free after all previous manipulations, was occupied by the middle motor (Medium motor), which actuates the cuckoo. The cuckoo itself is assembled from parts of the same Lego technics. The height of the bird reaches 11 units and is placed on a sliding bar (on such in the above-mentioned crane there are outboard supports). A miniature mechanism introduces a transfer between the wings of a bird and its tail, through which I threw a cable fixed inside the watch. The length of the cable is chosen in such a way that the cuckoo completely leaves with the wings down and only at the very end of the movement slightly spreads them to the sides. It turned out to be atmospheric - just at the level of mechanization of simple models of watches. The absence of a position sensor is compensated by the fact that the cuckoo drive is switched on through the slipping gear — it allows you to not damage the engine, even if he tries to move the cuckoo beyond the boundary points. The doors are rigidly connected with the lath on which the bird is fixed, and open simultaneously with the departure of the cuckoo itself.

Initially, I used 11 by 5 for 1 units as doors, but this turned out to be a bad idea: their edges were not rounded, and the doors, clinging to adjacent parts, were often blocked, leaving the cuckoo inside. The video shows the second version of the door assembly - the usual strips with rounded edges do not cause such a problem. In addition, the "strip" version of the door opens and closes much quieter.

The clock is mounted on a plank bolted to the wall. The whole structure weighs more than a kilogram.

In this description of the mechanical part, in principle, ends. It remains only to mention that the model is 100% assembled from Lego Mindstorms and Lego Technics, and the only part that does not belong to these sets is the power cord, which I soldered to my EV3, so that I don’t have to change batteries in hours. This wire goes to the power supply included in the outlet.


Build ev3dev provides banding for many programming languages. In order not to have difficulties with the assembly, I decided to limit myself to the Python script. This script is available in the GitLab repository . Below I will briefly go over its functionality.

The code that moves the arrows is relatively simple - it recounts the minutes and hours into the degrees of rotation of the engines, using data on the number of degrees of the engine per turn of the arrow and the initial displacement of the arrow from the vertical position. All the fun begins when the program tries to get this data.

As I have already said, it was decided to abandon the manual eyeliner. Instead, at start-up, the clock performs a calibration, determining the parameters of the geometry. Calibration is performed for both arrows independently of each other.

The calibration algorithm is as follows. First, the engine starts to rotate at a relatively high speed (I use an empirical value of 180 degrees per second) until a confirmation signal comes from the button that fixes the upper position of the arrow. After that, the engine resets the speed to 30 degrees per second and continues to rotate the arrow clockwise (the direction of rotation of the engine is sewn in the program) until it is separated from the point of the last opening of the button by 70 degrees. After this, the arrow passes through the upper position in the opposite direction, fixing the first short circuit and the last opening of the contacts (the button may rattle in the edge positions). Moving away from the last interruption by the same 70 degrees, the arrow again changes the direction of movement to a straight line,

It is considered that the upper position of the arrow corresponds to the arithmetic average between the four values ​​thus obtained. Practice shows that this approximation is quite good - the deviation of the target position of the minute hand from the actual rarely is more than 1 step and almost never exceeds two steps. (The video shows more significant deviations due to the fact that for shooting purposes I translated the system time, and the hands moved faster than during normal operation, increasing the correction error on each turn, see below.) For an hour hand, the backlash eats precision, but the algorithm, of course, uses the same one.

Having calculated the upper position of the arrow and the difference between the first switching on of the sensor and actually the upper position of the arrow (this value is required for correction, see below), the calibration algorithm again increases the engine rotation speed to 180 degrees per second and repeats the procedure for searching the upper position. The difference between two consecutive upper positions determines the length of the full turn of the arrow in units of engine rotation. The procedure for finding the top position is repeated five times, which allows averaging the values ​​obtained and slightly increasing the accuracy.

After the calibration is complete, the hands go to the current time display mode. In this case, on each circle of the arrow, the algorithm fixes the position at which the first circuit breaker closure occurred. The difference between the actual and expected angles of rotation of the engine at this point is the amount of correction; thus, even if the length of the full circle was calculated incorrectly at the calibration stage (the debug output shows that the deviation rarely exceeds 1 degree), the correction on each circle does not allow the needle to shift over time due to the accumulation of error.

Please note that the only information about the relationship of the engine and the arrow, which is explicitly wired into the program, is the direction of rotation of the engine (direct or reverse), corresponding to the forward motion of the arrow. Thanks to the position sensors, the need for data on the gear ratio and the initial position of the arrow disappears. Thus, if you collect clocks, in which, besides the hour and minute, the second hand will also be presented, the algorithm will allow you to use it by adding just a few lines without wasting time on recalculating the teeth.

What the shooter’s movement program doesn’t have is overflow protection or loss of accuracy. I did not investigate the question of what will happen earlier: the capacity of the angle of rotation of the engine will overflow or the arrows will start moving in spurts due to the departure of precision to the higher digits of the floating-point number. Nevertheless, practice shows that at times of the order of a few weeks, nothing of the kind happens. If I ever meet this problem, I will most likely just add an engine reset command on each lap, with the appropriate correction of angles in the program.

If the class Hand in my program is responsible for the movement of the arrows, then the LedIndication class lights up, then turns off the LEDs on the front panel of EV3. I know that the same effect can be achieved with one team, but initially this feature was intended for tracking program crashes, and then it remained. There is nothing more interesting in this class.

The Pendulum class is responsible for the movement of the weights and the pendulum. The algorithm simply starts the engine in one direction and rotates it at a constant speed until the button corresponding to the full lift of the given weight is clamped; after that the direction of movement of the motor is inverted.

In this class, by the way, presents protection from the departure of the program, which is that the engine is switched on for only 2 seconds with a command refresh period of 1 second. If I had turned on the engine in the constant rotation mode, then when we started the weight program, I would push the button and continue to move upwards, which could overload the motor, slip gears, or even damage the mechanism. Protection allows you to prevent this problem.

Finally, the Cuckoo class starts the cuckoo every time the value of 59 minutes is replaced by the value of 0 minutes. First, the cuckoo extends as far as it will go, then kukat once, reproducing the sound through the EV3 speaker, and then hiding again in the watch case. The movement is repeated in accordance with what is now the hour - from 1 to 12 times. The sound was taken fromFreeSound library and edited to sound better on EV3. (I can not say that I was pleased with the result, since the bass when you hit the hammer on the spring is almost inaudible.)

The delay between the cuckoo's takeaway team and the sound reproduction team was chosen experimentally so that the sound could be heard around the time the cuckoo reaches the extreme position. With this, however, ev3dev has a slight problem: because of the system boot, the sound periodically lags behind, especially if there is an SSH connection to the clock at this point. The delay can be up to several seconds. I'm not sure if this is a problem with my controller, the build itself, or updates taken from the network (after installing ev3dev, I habitually introduced the apt get upgrade command, although I probably shouldn't have done this), but on average, the cuckoo sounds normal, so debug this question I'm not going.

By the way, a bug in one of the earlier versions of the program was connected with the delay of the sound, when I hadn’t added the wait for playback to finish: if the cuckoo had time to hide and reappear during the delay, the next sound was “swallowed”, number of hours. Later I modified the program so that the cuckoo waited for the end of the sound in the extreme position and only then left for the next cycle.

Half-hour intervals are voiced by a single signal received from the same original sound. The cuckoo does not appear.

The rotational speed of the engine that drives the cuckoo, and its angle of rotation is protected in the program. At the start of the program, the cuckoo tightens into the body - taking into account the slipping gear installed on the motor axis, such an operation is safe, but it has an effect if at the time of starting the clock the cuckoo was outside the body.

In order not to interfere with sleep, the cuckoo only cups during the day. Her workday starts at ten in the morning, and the last time she voices is midnight. I also turned off the cuckoo at the time when I have weekly work calls on Skype, so as not to interfere.

The program is installed as a service and starts when you start Debian. Thus, it is enough to turn on the clock, and they do everything further. The time is taken from the Internet - in my EV3 there is a WiFi dongle. After the clock has started, I usually turn off the network, so as not to create an extra load on the processor.

The program is available under BSD license. If you have a desire to build a similar model and use my software, I will only be glad.

Also popular now: