Electronics and seals: we collect a robot toy for a cat on STM32
Good afternoon, dear habrovchane. A lot of time has passed since the last time I wrote articles on development here, it's time to fix this thing. In this article I will talk about how I assembled a small robot on the STM32F101 microcontroller to entertain my Maine Coon, Arthas, about what problems they had to face and what came of it.
Background and formulation of the problem
Half a year ago I had this black handsome Maine Coon, whom I named Arthas after the famous computer game hero.
The cat is incredibly playful, loves to run, ambush and even bring a ball like a dog. Since I haven’t collected anything for a long time, it was decided to develop a small toy for a cat. The main requirements for it were:
Protection of critical parts of the structure from cat teeth and claws, ideally, fully enclosed body (ball)
From the previous paragraph follows the requirement for small dimensions of the device, since it is desirable that it still was a small ball, and not a soccer ball.
The ability to control from a mobile phone / tablet and desktop computer - in order not to reinvent the wheel and ensure compatibility with mobile devices, Bluetooth connectivity is ideal.
To make it more interesting, it is desirable to have at least some sensor that would allow in the future to make the robot more or less autonomous, and not just a radio-controlled machine.
Having some way to get the sound out to attract the attention of the kote.
')
Immediately I will demonstrate a short video of what happened, the koshkob was launched in test mode (controlled by me, from a computer):
Koshkob tested without the outer shell, makes sounds cat attracts and can not escape becauseone of the drives fails. (More about this at the end of the article)
Koshkob complete
It may seem to some that the cat is not very actively responding to the robot, but in fact the reason is that during the test it has already snatched it from me a hundred times, carried it away and gnawed. Of course, I took away the robot (until it is finished), so the cat, seeing the robot on the floor, decided to wait some time to make sure that it was not taken away from him as soon as he attacked)
Next, I will talk about the development process itself.
Development: selection of components and preparation
Housing
Having decided on the proposed design, I purchased a pair of plastic balls consisting of two halves — one with a diameter of 60 mm and the other with 80 mm, in case the first one fails to fit. Such dimensions greatly limited the choice of engines and sensors (in the sense that, for example, an ultrasonic sensor could be forgotten, it would not fit in the ball and, moreover, would not work in an enclosed space.
Microcontroller
After cutting off the "ear", the balls became ideal candidates for the role of the body. Due to the limited size, it was decided to design the entire schematic using the most compact cases, that is, for the most part, QFN. STM32F101 was chosen as the central processor, since it is a microcontroller on the Cortex M3 core, and not a truncated M0, while it can operate at 36 MHz, has 64 KB of flash and 16 KB of RAM, and, most importantly, comes in 6x6 mm QFN -casing
Sensor
As a sensor, a three-axis accelerometer LIS331DL from the same ST was chosen, which was just a discount in Terraelectronics, so I got it at a price of about 30 rubles per item.
The accelerometer is available in a QFN case, 3x3 mm and can communicate via the I2C bus, which is very useful in conditions of limited dimensions. With the help of an accelerometer, it is possible to subtract the tilt of the robot along three axes, and it is also possible to try to get information from it about whether the robot is moving or has run into an obstacle (by changing the acceleration). And, of course, determine the time at which the cat kicks him to make a squeak - so the cat will consider it to be something alive)
Connection
As a means of communication, of course, we take proven, cheap and small Chinese modules HC-05 This is the only finished module in the robot.
Sound source
Initially, I wanted to use compact speakers, but, unfortunately, even the smallest speakers were still very large. In addition, they consumed a great deal and demanded at least a transistor and a filter in order to shake them with WMA. After some amount of googling, I found just such an entertaining piezo-squeaker: Murata's PKLCS1212E4001 costs 48 rubles, has dimensions of 11x11 mm (the largest element on the board!) And is a standard Piezo Sounder, a device that makes a sound due to the bending of a membrane by the piezoelectric effect. And this means that it consumes an order of magnitude less current than a speaker squeaking at the same volume. But, in contrast to the dynamics of her very tricky and uneven frequency response, so that the best she knows how to squeak. And the loudest she gets to do it at 4 KHz (but this does not mean that you can’t squeak at others!)
Drives
The most important element is the drives that will move the robot. Unfortunately, everything was not as smooth with them as we would like, more on this at the end of the article. As drives, I decided to take the smallest servos that I could find and remake them for constant rotation. My choice is explained by the fact that by taking servos I get a motor + gearbox + control board in a housing of about 15x20x8 mm. With all the desire, I could not find a gear motor of such dimensions. As a result, the choice fell on sub-micro servas , at the price of 187 rubles per share:
Nutrition
All elements are selected, it remains to decide how and what to feed the system. Obviously, the smallest lithium-polymer battery is the smallest and most suitable source. Since the drives require 4.8V, we increase the voltage to 5V with a compact DC-DC converter from MAXIM Semiconductors. The MAX8815 is a superb 3x3 mm microcircuit that allows you to load up to 1A with 97% efficiency (which, of course, depends on the correctness of the PCB layout, operation mode and choice of strapping, as always). Since the drives consume no more than 600 mA together at peak times, this is more than enough.
To power the rest of the electronics and protect it from interference from the engines, after the DC-DC boost converter, we put a small-sized linear regulator from TI, LP2985 , with a fixed 3.3V output.
Circuit design and some design
First, a few words about the design of the robot. In order to minimize the size and cost, I decided to use printed circuit boards as structural elements. That is, the drives are clamped between two printed circuit boards, which are fastened with screws. Assembled (and after debugging modifications of the board, which are later), it all looks like this:
To prevent the drives from moving down, I put wonderful material between the board and their surface - latex from the Torres expander
The fact is that once I bought a slingshot in China. The cattle was very comfortable, made of titanium alloy, but the rubber was not to hell there. On the Internet, experts on slingshots advised to immediately throw it out, to buy this very expander, and to cut out replacement harnesses from it. The result exceeded all my expectations and the slingshot became incredibly powerful. And since The expander is a big thing, then most of the material remained untouched and lay in a drawer, waiting for its time. After using this latex as a gasket between the drives and the board, the drives stood up like a glove, not moving a millimeter.
Accordingly, for the implementation of this design requires two boards, in which all components are focused on the outer sides. Once we have such a sudden increase in usable area, on the bottom board you can place a battery charger, a mini USB connector, charging LEDs, and at the same time bring a BT module so that it does not cover the battery and does not interfere with communication. Thus, two PCBs, TOP and BOTTOM, were developed. On the bottom is what I have already said, and on the top is the whole “brain” and, so to speak, the digestive system of the robot - a microcontroller, an accelerometer, a converter and a power regulator strapping and, of course - a piezo-squeaker.
The scheme of the top board looks like this:
Power scheme
Brain
In order for USB not to drive its five volts where it is not necessary, the ON inputs of the U1 converter and the U2 regulator are connected, pulled up to power and brought to J1 on the edge of the board — the GND level feed puts the converter's inputs and outputs into a high impedance state, essentially breaking the circuit and letting the USB current flow where it should be — into the battery charging circuit. The rest of the connection scheme is typical of datasheet.
The U4 accelerometer is connected to the I2C bus of the controller without pull-up resistors - yes, they are necessary for the bus to work, but in the datasheet they assert that they are connected inside the LIS331DL . Strangely enough, there is no more information about them, I never recognized the nominal (and in the off state it is not measured, apparently, they are disconnected from the bus by transistors). So I had to blindly rely on datasheet. I must say, in this I did not lose - the accelerometer actually works fine without additional resistors. However, another major fac-up was associated with it, which you can read about in the “Testing and Facs-ups” section.
In addition to the accelerometer, a D1 LED is connected to the controller, which is intended to visually attract the cat's attention and serve as a means of indication, as well as a voltage divider on resistors R4 and R5, which is connected to the ADC input of the controller through a smoothing capacitor C5. This divider leads the battery voltage to the range that ADC can measure, making it possible to judge the level of battery charge. Incidentally, a mini-factor was connected with these resistors. The fact is that I assumed the presence in the controller of the built-in reference voltage (about 1.2 volts), as in the older models. But, as it turned out, in the models in the QFN36 case, there is no built-in source, and the REF input inside the case is shorted to the supply voltage (3.3V), so the resistors that at 4.2V battery gave 1V at the output had to be changed to those that give 3V .
The LS1 squeaker, thanks to its piezo essence, can be connected directly to the controller pin - its consumption is very small, at its resonant frequency its impedance is several hundred ohms. The only potential problem is that it can work in the opposite direction, that is, to generate voltage during deformation (shock), for which protective diodes or resistors are usually used. However, according to the results of the experiment, the voltage at the impact of an average force did not exceed 1.5V, which the protection diodes of the controller output can do well with, so I ventured not to put on additional protection.
The outputs from the onboard PWM generator of the controller are mapped to pins J8 and J9 to control the drives. As an additional (and, as it turned out, not superfluous) measures to reduce consumption in inactive mode, contacts J11 and J12, to which GND drives are connected, are cut off from ground by a power transistor Q1 - supplying a high level to the gate gives the drives a ground force and allows current flow through their insides. As it turned out, even at zero PWM signal, the control circuit of the drives still supplies some voltage to them and the consumption increases by 10 mA compared to completely disconnected ones.
An important point was the choice of debugging interface. In conditions of very limited dimensions, of course, I wanted to do with the minimum number of wires. But the information about the minimum amount turned out to be quite contradictory. After thoughtful googling and experiments, I stopped at the SWD interface, removing only the SWDIO and SWCLK pins. Related to this is another fac-up described in the section “Testing and Facs-ups”. But in short - yes, these two pins are really enough for debugging in most cases .
The bottom board is quite simple:
Bottom fee
It contains two parallel Li-Pol (Li-Ion) battery charging linear circuits connected in parallel, LTC4054 from Linear Technology. This is the easiest way to charge single-cell lithium-polymers and lithium-ions, known to me, if not pretty low efficiency (which is due to the fact that the chips are linear). They stand perfectly in parallel, in some Chinese schemes saw as many as four similar mikruhi in parallel, providing a large charge current. Separately, each can give up to 800 mA, but this is only if you want to fry eggs on them. With a load above 500 mA and a fully discharged battery, the microcircuit begins to heat up so that it is impossible to hold a finger. Since A protection circuit for temperature is built into it, which, in principle, is not terrible - it will automatically reset the load current when it warms up to 120 degrees. But still this is not very pleasant, so I chose to put two pieces, since the place allowed. The charge current is set by resistors R4 and R5, selected by me so that it is about 500 mA for two (that is, 250 mA for each), at which they are not so heated.
In addition, the board has a mini-USB connector (J2), a Q1 transistor, a pull-up ON input of the power supply circuit on the top board to ground, with USB connected, and a Bluetooth communication module.
I ordered the boards at Rezonita, it came out quite budget-wise, I paid less than 2000r for a panel of six different boards, on which there were two boards from a cat-hobo. Top and bottom boards are 32x26 mm. After assembly (and before the fix-up fix), the top board looks like this:
And the bottom is like this:
It's time to write a test firmware!
Test firmware
I plan to make the final firmware based on FreeRTOS (so as not to waste time implementing normal multitasking, blocking queues and other things), but for the test I sketched a small firmware initializing all the peripherals and allowing it to be controlled by simple commands from the computer. Go through the initialization:
Everything is simple here - we submit the clock to all the peripherals we need, that is, to the I / O ports, the ADC, the UART, a couple of timers (one for a tweeter, the second for PWM drives) and I2C. Then we set up all GPIO.
Setup is reduced to the initialization of the timer, the output of which is connected to the squeaker. We adjust the PWM, but, in fact, it is the pulse width that will not be changed, always setting it to 50%. Instead, we will change the divider, forcing the timer to change the frequency of the pulses in order to squeak in a different tone. Since the system frequency is 36 MHz, we set the period to 4 (we still do not need a lot of PIMA discharge), and the prescaler is 1800, receiving a frequency of 4 KHz.
We do the same thing as with the beeper, but we are already sharpening the output of PWM with the parameters required by the drives, namely, the frequency around 50 Hz, and a sufficiently large number of digits to control the speed with great accuracy. Thus, we set the prescaler to 176, and the period to 4096, which gives us approximately 50 Hz and 12 bits of PWM.
Everything is simple here - for the accelerometer, we simply turn on I2C for a speed of 200 KHz (although it is possible more and less, the axel allows), and Bluetooth is our usual UART, which we turn on for standard 9600 and at the same time set up intercept reception in which we will process commands.
Next, write the UART interrupt handling code. Of course, it is not the most successful, it will not hurt at least to check the checksum, but it will do for the test. In order not to waste time on the command queue, let's make it equal to one team - it still only affects how often you can throw commands to the controller and not be afraid that he will let them through.
To begin, we will declare the structure of the command, which will consist of, in fact, the command itself, the state (completed, in the process of receiving, during processing), the packet length (including the two fields already listed) and the payload, which can be from 0 to 8 bytes . We describe a helper function for initializing this structure and another one for filling it with Invalid Command values. Now we describe the interrupt. Having received one byte on the UART, let's see what happens with the current command (the one and only one in the “queue”) - if its status tells us that the execution has been completed, then we will check if we received the correct opcode, if not, we will report an error, if yes, we will begin to receive a new command, setting the status to CS_RECEIVING . If we are in the process of receiving, we control the length of what we get - so that it does not exceed 10 bytes (2 bytes of the header and payload) and the length declared in the second byte of the header. If something is wrong, we report an error, otherwise we say that the command has been received and has passed to the CS_EXECUTING state. From this point on, we ignore everything that comes to us, until someone sets this team to CS_DONE . If we had a real queue, it would be possible to throw the received command into it and for now take the following.
That's all - the main function of the firmware simply initializes the peripherals, turns on the Bluetooth and waits until the command has the status CS_EXECUTING . After that, it processes the command (I will not give this code, there is just a big switch on opcodes with entering bytes from the payload to the registers) and sets it to CS_DONE status.
That's it, now the serv will always assume that its shaft is exactly in the middle. And by submitting a PWM signal with a duty ratio greater than the average, the output shaft will begin to rotate in one direction, and at less - in the other. And the more the filed value is separated from the average, the faster the shaft rotates.
Testing and Facs
Customer tests device prototype
Since I have already demonstrated the video and photo of the device above, this section will mainly contain a text description of the rake I stepped on. Some of them occurred through my fault, some did not depend on me.
Fak-up with food
The very first factor-up, entailed the most improvements in the scheme. Connected to the boost converter. When I first started the device (so far without drives), I didn’t notice anything, the controller started up and flashed. 5B were present at the output of the converter. The time has come to check the drives, this is where the rakes came out. When connecting the drives, the converter was instantly cut off - its built-in protection triggered, disabling the microcircuit, in case the output voltage drops more than 10 percent below the set point (5V). Debugging took me a very long time, including sitting at an oscilloscope, replacing the converter chip itself with a similar one, testing different chokes, etc. Interestingly, even the containers hung around the drives did not help, so I decided that the problem was in the PCB layout or in the choke. Measurements have shown that the converter stops working at a load of more than 90 mA, and even in the case of a pure resistive load! At the same time, the efficiency was about 40 percent, of course, this is unacceptable for a pulse converter.
The reason turned out to be incredibly commonplace - it seems that instead of the output ceramic capacitor of 10 µF, I mistakenly soldered the same to 1 µF. With such an output capacitance, the microcircuit could not reach the mode, and the large capacitors mounted on the snot did not help it at all. Lightly stripping the board from the mask, I soldered two 22 microfarads of ceramic capacitor to the converter output, to its input, and right in front of the servos. At the same time I set a smoothing choke (more precisely, ferrite bead), BLM41PG471SN1 , calculated for 2A, between the output of the converter and the servers. In addition, as it turned out, the place on the board allows you to push there one tantalum capacitor in the “A” case, 150 μF, right next to the converter output. In fact, one 22 microfarad capacitor at the output and one at the input would be enough for correct operation, but since space allowed, I decided to play it safe. The result was just great, the 5V output, even under load, was almost not noisy, and the converter's efficiency, according to my measurements (I included ammeters in the input and output circuits), reached 93 percent, which is a very good figure in itself.
Conclusion from the FAQ: Check which elements are soldered to the board. Pulse converters are sensitive, and the components mounted on snot will not improve the situation, even if the direction of thought (insufficient output capacity) was correct. The resistance of the probes and the shunt of the multimeter, the capacity and inductance of the prototypes distort the picture, so it is necessary to test such things in the final configuration, and not on snot.
Fac-up with accelerometer
Hemorrhoid fak-ap, again because of inattention. When testing the periphery, it turned out that the accelerometer is not responding. Since He sits on the I2C bus, the conversation begins (not counting the starting impulse) by passing the address of the device. After that, it should respond with a confirmation pulse, if the address coincided. There was no impulse. Since the accelerometer case was the most disgusting for soldering (3x3 mm and there was no earthen pad on the belly of the chip, which made it disgustingly centered), I decided that the problem was soldering and spent a lot of time re-soldering it several times. Did not help. Then I decided that the promised built-in resistors were still insufficient, cleaned the board and soldered their own. Did not help. Many times I checked the code and checked the address with the datasheet. Did not help. As a result, by some miracle, he gave an address that differs from the one given (in one of the digits of the binary representation of the address). It helped. I started digging datasheets, because this simply could not be - so that the device responded to another address. And found a great thing. It turns out that there are two modifications of the accelerometer: LIS331DL and LIS331DLH . The same case. Same datasheets. . 2g/4g/8g, — 2g/4g. . , LIS133 «LIS133DLH», , .
-, . , SWD — . , (ST-LINK ), VAPP . , - 3.3. , , — . . NRST , , , . SWD , , . But. . , 32, Debug support for low-power modes : The core does not allow FCLK or HCLK to be turned off during a debug session. As these are required for the debugger connection, during a debug, they must remain active. , Stand-By, . And since -, . — - , - ( ), , NRST . , , , -, . GND, , - . , , .