01/15/2017 at 11:34 •
As I wrote in the previous logs, I'm going to be upgrading Tote to use some more expensive, but more powerful and easier to use components. But what about the poor students? If you are really concerned about the budget, the original Tote is almost what you need. Almost, because you would still need to order the PCB for it. Or would you?
Of course not! The PCB doesn't have anything you can't easily reproduce on a vero/strip/perma board! Here's one example of a Tote on a strip board:
Sure, you will need to remap the pins in the code, but that should be quite easy. Yes, I went wild in Fritzing, and it's barely readable. Here's a clearer picture of the strip board you will need to make:
It even has the voltage divider for monitoring the battery. Oh, right, and don't use alkaline batteries like on the picture. Use a LiPo from a quadcopter or from an old cellphone.
I have to admit that one thing they say about Fritzing is true: it sucks for making schematics:
I wonder if I should fork this version off the main Tote, and keep a repository with the Arduino code for it, with remapped pins and so on...
01/14/2017 at 14:11 •
n the previous log I made a decision to use an Adafruit Feather board for the robot's brains, and a bare ATmega chip in a DIP package for its spinal cord -- that is, the servo controller. That's supposed to make the board much easier to solder even by inexperienced builders. But wait a minute! How are they going to get the servo controller program onto those chips? Will that not require some extra hardware? Sadly, yes.
It will require six extra wires.
The trick is to use the Feather board as an ISP programmer, using the "Arduino as ISP" example sketch from the Arduino IDE. You will need to make the following connections:
Now, in your Arduino IDE go to Files→Examples→11.ArduinoISP and select that example. Then scroll to around line 68 and change this:
// Configure which pins to use: // The standard pin configuration. #ifndef ARDUINO_HOODLOADER2 #define RESET 10 // Use pin 10 to reset the target rather than SS #define LED_HB 9 #define LED_ERR 8 #define LED_PMODE 7Into this:
// Configure which pins to use: // The standard pin configuration. #ifndef ARDUINO_HOODLOADER2 #define RESET 0 #define LED_HB 2 #define LED_ERR 4 #define LED_PMODE 5Then go to Tools→Board and select the Adafruit HUZZAH board, then do Sketch→Upload. You have your programmer ready.
Then to program the chip, load the sketch with the servo controller, change the board to Arduino Uno, select Tools→Programmer→Arduino as ISP, and do Sketch→Upload Using Programmer. You should see some blinking lights on your Feather, and then your chip is programmed.
In the end, I will probably make a Makefile that does the equivalent of the above procedure automatically, to streamline the experience a bit.
01/11/2017 at 22:28 •
In the previous post I shared some of my thoughts about this project, and decided to pick a different development board than the Pro Mini that I have been using so far. Don't get me wrong, Pro Mini is great for all kinds of small and cheap projects, it's just that I want to make programming this robot as simple as possible. That, among other things, means using a platform that has a lot of computing power, not just enough, preferably one that has so much of it, that it can be used with a high-level language like Python. That also means something that has a USB socket.
The plan is to keep the Tote base PCB for its body, and keep the ATmega microcontroller on it, but make it only serve as a servo controller. Then, on top of it, have headers for plugging in the actual brains, and possibly for stacking additional shields with sensors and other peripherals. The board would only need connections for the power and the I2C pins, but since there is no standard for the pin layout (or, rather, there are lots of standards), I need to choose one -- history shows that trying to make it flexible and compatible with many different boards only leads to pain and suffering.
However, I still want this to be relatively cheap. It would be bad if the brain was more expensive than the ~$20 the legs cost. I first tried with the D1 Mini board, because it's my favorite ESP8266 board, it's small and compact, and it has a number of shields for it available. It's also easy to make new shields for it, and they can be very small, which makes them cheap on OSHPark. The board can run MicroPython and has WiFi build in, which makes it easy to use a remote console to program and debug it very conveniently. There is also a LiPo shield, which makes it possible to recharge the battery from the USB. So I spent some hours making this:
The base is just the #Servo Breakout for WeMos D1 Mini with 20 channels for the servos. I tried to make it easier to reprogram by including the ISP header. There are no Tote-specific markings about leg servos and so on there -- just channel numbers, so it makes it easier to see which servo is which inside your program, where you have to refer to them by numbers too (at least initially). This way there is no hardcoded magical knowledge necessary, and you can use the remaining 8 PWM outputs for other things, or use this board with a different legs configuration than Tote has.
There is also a power switch in there, but it's not connected to the rest of the board -- since I didn't decide about how it will be powered yet (you can have the LiPo shield or not, you can have some other charging/protection module, you can use a powerbank, etc.), I left it disconnected and only provided headers. I also added battery connectors on both ends of the board, for use with any battery holder. Unfortunately, I didn't know which one, so I just spaced them as far from each other as possible.
Then there are the headers for connecting the D1 Mini and its shields. I used alternating holes headers, so that you can plug it directly into the PCB (but you can also use headers). I connected the servo power to the 5V pin, to bypass the voltage regulator on the board.
Later, I found a tube of ATmega328 chips in the MLF package, and I was a bit bored, so I made a version for that, playing with Fritzing's curvy traces:
It was fun, but ultimately unproductive. Anyways, I liked the first board, so I ordered it at DirtyPCBs and went do bed.
I couldn't sleep that night.
Tossing and turning, I started thinking about different options I have for using this. Then the doubts crept it. If I use the LiPo shield, there will be a boost converter on the 5V line that powers the servos. Will it have enough power for all those servos? If not, can I somehow power the servos directly from the LiPo? I don't have a connection for that on the board, should I add it? What will happen if I short the 5V pin with the 3.3V pin on the D1 Mini? Will that damage the voltage regulator? Can I make adapters for the D1 Mini pinout for other boards? What if I wanted to use OpenMV, could that work? Which of the official D1 Mini shields would actually be useful? The temperature and humidity sensors? The button shield? The single WS2812B RGB LED? Will there be enough room between the robot legs to place the board under the body instead of on top? And so on.
Finally, at 5am I decided I'm not going to fall asleep anyways, so I could as well do some mock designs. What other ESP8266 development board do I know that has a lot of shields available? Maybe the Adafruit HUZZAH Feather? It's a bit expensive, but it does come with a LiPo charger built-in, the correct pin markings for MicroPython (the D1 Mini uses the NodeMCU markings) and generally has great support. There are also other Arduino-compatible boards with that footprint, and there is an M0 board that also runs MicroPython. And the shields somehow look more appealing.
So I decided to give it a try, and I came up with this:
Unfortunately, the Feather is a fraction longer than the 5cm of the Tote's base, so it sticks out about 2mm in front. That's where the ESP8266's antenna is, so I guess that's fine. I also made a couple of other decisions here.
Since there is no boost converter, only the charging circuit, I have no problems with servos drawing too much power -- I will just power them directly from the battery. I decided on the kind of battery to use -- I discovered the 16340 lithium batteries. Previously I knew the 18650, as they are commonly used for power banks, but those are too big for Tote. The 16340 is half that size, and there are convenient battery holders for it. So I added holes for mounting such a holder on the bottom of the board, and made all the connections for the switch and the charging circuit, etc.
I also decided to use one of the analog-only pins of the ATmega for battery voltage monitoring, since I wasn't using them anyways. It's the same voltage divider circuit I had in the previous Totes.
One more addition, is the double pin header on the front. I plan to add a female header to it, but soldered flat on the board, so that you can easily plug any sensor breakout boards into it, and they will be facing forward. Of course, you would need to make any connections with additional wires, but at least there is the mechanical support.
But something wasn't quite right. I had this nagging feeling that I'm forgetting something. I reviewed my notes, and then I realized. Tote is supposed to be simple to build without access to special tools like 3D printers or laser cutters. Or like reflow ovens, hot plates, hot air guns or very precise soldering irons, like the one I have. I have SMD parts on that board, and no beginner is going to solder that with a cheap soldering iron, without using any flux. This board is simply too complex for Tote. I need something simpler.
So I deleted the microcontroller and all the SMD parts, and started working again. I came up with something like this:
There is a number of changes. I used an ATmega chip in a DIP package, which should be easy enough to solder with a rusty nail. There are no analog-only pins in that version, so the battery monitoring went away. I connected the reset pin to the Feather's reset, so they share the pullup resistor there. And I'm going to use internal pullups for the I²C lines.
Next, I aligned all the headers with each other, so that it's easier to solder them all by inserting them into a breadboard for holding. I had some room on the sides, so I doubled the Feather's pins, making a prototyping area where you can connect those wires from your sensors, or whatever you want. I also disconnected the second ground pin from the ground, as I realized that it's connected to CH_PD on the HUZZAH, and I would get a short there. As a finishing touch, I added all the labels I could think of, and moved them to more convenient places. I also added ground fill and some silkscreen decorations that are not shown here, for clarity.
DirtyPCBs has this awesome feature, where you can change your order's gerber if it wasn't assigned to a panel yet. I checked my order, and it wasn't, so I quickly swapped this. I think this is the design I'm going to go with. It's easy enough to assemble even for a beginner, provides a lot of room for prototyping, and is simple and modular.
It's funny how bigger components, like the DIP chip and the Feather board, actually give me more room on the board. The DIP chip has much better spacing of the legs, so I don't need as much width for fitting all the traces. The Feather is narrower than the D1 Mini by 2.54mm, but that means you can fit two Feather shields (they call them Wings) on a 5x5cm PCB, and you have room for the servo horns on the sides of that base board. Finally, you can use a DIP socket and make the chip pluggable -- so you can easily replace it, and also reprogram it more conveniently.
I'm really excited about this board, and I think this is really the right direction for Tote to go in. The next step is code and documentation for it. If the prototype works well enough, I'm going to make it the default version in the documentation and only focus on this. Can't wait for the boards to arrive.
01/11/2017 at 16:15 •
This is one of my oldest projects, and definitely one that I have put the most total work into so far. With the year's end, I decided to reflect a bit about the progress made so far and the way forward.
There wasn't a lot of activity, but some interesting things did happen last year.
We had a workshop in Belgrade, where we built 20 #Tote HaDs. I have learned a lot about how (not) to source parts for such an event, how to run it, what parts are actually hard for people, etc. There were also some improvements to the construction itself contributed by the participants -- but only during the workshop. I'm a bit disappointed that nobody seems to have done anything with their robot after the workshop -- or, at least, I haven't heard about it. I think this is an important point to consider.
There have also been some Tote-inspired builds out there. I helped to build at least two of them. There are even more unfinished projects, but I guess that's normal.
On my side, I released another version of the PCB, experimented with some alternate brains (including the #Tote Zero with a Raspberry Pi), and made one of my prototypes look much better by giving it a chassis and some LED eyes, and a coat of paint. There has been practically no progress on the software side, despite some research on the CORDIC algorithms and servo PWM code. I also didn't experiment much with sensors and behaviors. The step-by-step tutorial is also empty.
Overall, even though some work got done, and even though I gained some experience, I'm not particularly happy with the outcomes of the Tote project. I'm starting to realize that it's not enough to give people a platform to experiment with -- even if they do experiments and improvements, it's all for nothing if they don't share them.
I think that part of the problem is that I have been focusing on the wrong parts of the project. I need to pause and re-evaluate some of the assumptions I made, and see where that takes me.
When I was just starting with Tote, I still remembered being a student and not having much of a budget for this kind of projects. So I made lowering the total cost the number one priority (well, apart from having it actually work, of course). As I look at this now, this might have been a mistake. Sure, when you are a student in Poland, price is the number one factor for anything. But it turns out that most people who do this hobby stuff actually don't mind spending a little bit more if that saves them time, makes things more convenient, gives better results or even just makes things look more shiny. If you are going to put hours of work into a project anyways, you don't mind waiting a little bit more to get the extra funds. So I am going to pay less attention to the price (but still try to keep everything frugal) from now on.
By default, Tote is controlled with a TV remote, and has no autonomous functionality. I did that, because I figured it's the simplest starting point, and also shows off the hardware capabilities, leaving any software-side innovation to the users. Or maybe I was just lazy. In any case, I think that this has turned it into a toy, and discouraged actually programming it. There are some other decisions that also contributed to it: the need for an external programmer for programming, the main code written in C++, no easy way to update and debug the code. I think I should start putting more effort into making it easier to actually program this robot, and encourage it more. Fast iteration is the key to good progress. I have become painfully aware of that recently when working on the recent version #µBob biped robot, where I had to physically unscrew and detach the legs to access the chip for programming. That's the best way to make sure nobody ever changes anything in the program unless they absolutely must. So I need to try and remove all the obstacles for programming. And also finally finish the programming tutorial for it.
Simplicity was another design goal (it always is), but I kinda lost track of it in my pursuit of squeezing as much as possible from the small budget. It especially shows in my The Way Forward log a few months ago and the crazy PCB design for Tote Zero. Something definitely went wrong there. I really need to break up the whole design into independent, single-function modules, and I need to work on lowering the complexity of each of them -- preferably using ready off-the-shelf parts and modules. I also need to look into making the assembly easier. One of the goals from the beginning was to not require any special tools like 3D printers or laser cutters -- so that you can make it at home easily. However, I forgot that soldering skills are also an "advanced tool", and that while many people have access to some way of soldering, soldering tiny, densely packed SMD components is not a common skill. So I definitely need to review that.
Sourcing the parts is a problem too. From the start the goal was to use standard, off-the-shelf, easily available components, and I did follow that. However, in my pursuit to make things cheap and also to make it easy to reuse whatever parts you might have lying around, I left a lot of things underspecified. The battery is an excellent example of that -- I'm mostly using LiPos for toy quadcopters, because they are cheap, light and can provide a lot of current. But every manufacturers makes them in a little bit different sizes, with different plugs (they especially love to swap the + and - leads), and generally storing and charging them is a bit involved. Because of that, my designs just leave the battery out, assuming the user will use whatever he has, and will attach it whenever it fits, usually with a two-sided tape, or maybe velcro. That's definitely sub-optimal, and I need to put more focus into specifying the parts a little bit more precisely and using more standard ones. It's also a very daunting task to order a couple of servos in one place, a battery in another place, the pcb in yet another place, the mcrocontroller board in yet another, etc. -- I think that this stops many people from trying this project. Of course, the obvious solution would be a kit, but I don't want to be selling anything... Perhaps I should try looking at Tindie anyways?
Finally, but perhaps most importantly, I need to find a way to disown this project, to make it a brand of its own, and not something attached to my name. I think that most people, when they build a complex project like this, like to "own" it, make it their own -- and not say "I've build Radomir's robot". I haven't figured out how to do that yet. Perhaps I will need to team up with some other similar projects?
I definitely want to continue working on Tote with the goal of crowdsourcing innovation in the area of quadruped robots. There will probably be some large changes, though, as a result of the above goal changes. I will probably use a different development board, something that has shields. I will try to make the battery and power more manageable, and I will put more focus on the documentation and software side of things.
12/22/2016 at 14:48 •
It took me two evenings of pretty much randomly editing code, trying to make it as small as possible without breaking it horribly at the same time, but I finally have a library with three basic functions, iasin, iatan2 and isqrt, which are int16_t versions of the ones from the standard library. The angles are returned in the range of -1800 to 1800, and the input to asin is -1<<13 +1 to 1<<13. The whole library is around 700 bytes (644 at the last compile) and should be relatively fast on the AVR (although I didn't really time it). Oh, and the code is at https://bitbucket.org/thesheep/imath/src/tip/imath.c
If you see any opportunity to shrink it even more, please tell me!
Unfortunately, this is still way too large to make Tote fit in the magical kilobyte. I might try with int8 versions next, but those are not going to have enough resolution for a proper walk, unless I will play with the ranges some more.
Here's a comparison of the values from those functions with the standard library:
asin(-0.88)=-61.04 iasin(-7168)=-610 diff -0.04 asin(-0.75)=-48.59 iasin(-6144)=-486 diff 0.01 asin(-0.63)=-38.68 iasin(-5120)=-388 diff 0.12 asin(-0.50)=-30.00 iasin(-4096)=-302 diff 0.20 asin(-0.37)=-22.02 iasin(-3072)=-220 diff -0.02 asin(-0.25)=-14.48 iasin(-2048)=-144 diff -0.08 asin(-0.12)=-7.18 iasin(-1024)=-70 diff -0.18 asin(0.00)=0.00 iasin(0)=0 diff 0.00 asin(0.12)=7.18 iasin(1024)=72 diff -0.02 asin(0.25)=14.48 iasin(2048)=144 diff 0.08 asin(0.37)=22.02 iasin(3072)=220 diff 0.02 asin(0.50)=30.00 iasin(4096)=300 diff 0.00 asin(0.63)=38.68 iasin(5120)=388 diff -0.12 asin(0.75)=48.59 iasin(6144)=486 diff -0.01 asin(0.88)=61.04 iasin(7168)=610 diff 0.04 asin(1.00)=90.00 iasin(8192)=916 diff -1.60 sqrt(0)=0.00 isqrt(0)=0 diff 0.00 sqrt(1024)=32.00 isqrt(1024)=32 diff 0.00 sqrt(2048)=45.25 isqrt(2048)=45 diff 0.25 sqrt(3072)=55.43 isqrt(3072)=55 diff 0.43 sqrt(4096)=64.00 isqrt(4096)=64 diff 0.00 sqrt(5120)=71.55 isqrt(5120)=71 diff 0.55 sqrt(6144)=78.38 isqrt(6144)=78 diff 0.38 sqrt(7168)=84.66 isqrt(7168)=84 diff 0.66 sqrt(8192)=90.51 isqrt(8192)=90 diff 0.51 atan2(0, 0)=0.00 iatan2(0, 0)=0 diff 0.00 atan2(0, 1024)=0.00 iatan2(0, 1024)=0 diff 0.00 atan2(0, 2048)=0.00 iatan2(0, 2048)=0 diff 0.00 atan2(0, 3072)=0.00 iatan2(0, 3072)=0 diff 0.00 atan2(0, 4096)=0.00 iatan2(0, 4096)=0 diff 0.00 atan2(0, 5120)=0.00 iatan2(0, 5120)=0 diff 0.00 atan2(0, 6144)=0.00 iatan2(0, 6144)=0 diff 0.00 atan2(0, 7168)=0.00 iatan2(0, 7168)=0 diff 0.00 atan2(0, 8192)=0.00 iatan2(0, 8192)=0 diff 0.00 atan2(1024, 0)=90.00 iatan2(1024, 0)=899 diff 0.10 atan2(1024, 1024)=45.00 iatan2(1024, 1024)=449 diff 0.10 atan2(1024, 2048)=26.57 iatan2(1024, 2048)=274 diff -0.83 atan2(1024, 3072)=18.43 iatan2(1024, 3072)=183 diff 0.13 atan2(1024, 4096)=14.04 iatan2(1024, 4096)=139 diff 0.14 atan2(1024, 5120)=11.31 iatan2(1024, 5120)=112 diff 0.11 atan2(1024, 6144)=9.46 iatan2(1024, 6144)=95 diff -0.04 atan2(1024, 7168)=8.13 iatan2(1024, 7168)=84 diff -0.27 atan2(1024, 8192)=7.13 iatan2(1024, 8192)=70 diff 0.13 atan2(2048, 0)=90.00 iatan2(2048, 0)=899 diff 0.10 atan2(2048, 1024)=63.43 iatan2(2048, 1024)=633 diff 0.13 atan2(2048, 2048)=45.00 iatan2(2048, 2048)=449 diff 0.10 atan2(2048, 3072)=33.69 iatan2(2048, 3072)=336 diff 0.09 atan2(2048, 4096)=26.57 iatan2(2048, 4096)=274 diff -0.83 atan2(2048, 5120)=21.80 iatan2(2048, 5120)=216 diff 0.20 atan2(2048, 6144)=18.43 iatan2(2048, 6144)=183 diff 0.13 atan2(2048, 7168)=15.95 iatan2(2048, 7168)=159 diff 0.05 atan2(2048, 8192)=14.04 iatan2(2048, 8192)=139 diff 0.14 atan2(3072, 0)=90.00 iatan2(3072, 0)=899 diff 0.10 atan2(3072, 1024)=71.57 iatan2(3072, 1024)=724 diff -0.83 atan2(3072, 2048)=56.31 iatan2(3072, 2048)=562 diff 0.11 atan2(3072, 3072)=45.00 iatan2(3072, 3072)=449 diff 0.10 atan2(3072, 4096)=36.87 iatan2(3072, 4096)=370 diff -0.13 atan2(3072, 5120)=30.96 iatan2(3072, 5120)=309 diff 0.06 atan2(3072, 6144)=26.57 iatan2(3072, 6144)=274 diff -0.83 atan2(3072, 7168)=23.20 iatan2(3072, 7168)=232 diff -0.00 atan2(3072, 8192)=20.56 iatan2(3072, 8192)=206 diff -0.04 atan2(4096, 0)=90.00 iatan2(4096, 0)=899 diff 0.10 atan2(4096, 1024)=75.96 iatan2(4096, 1024)=759 diff 0.06 atan2(4096, 2048)=63.43 iatan2(4096, 2048)=633 diff 0.13 atan2(4096, 3072)=53.13 iatan2(4096, 3072)=534 diff -0.27 atan2(4096, 4096)=45.00 iatan2(4096, 4096)=449 diff 0.10 atan2(4096, 5120)=38.66 iatan2(4096, 5120)=388 diff -0.14 atan2(4096, 6144)=33.69 iatan2(4096, 6144)=336 diff 0.09 atan2(4096, 7168)=29.74 iatan2(4096, 7168)=299 diff -0.16 atan2(4096, 8192)=26.57 iatan2(4096, 8192)=274 diff -0.83 atan2(5120, 0)=90.00 iatan2(5120, 0)=899 diff 0.10 atan2(5120, 1024)=78.69 iatan2(5120, 1024)=786 diff 0.09 atan2(5120, 2048)=68.20 iatan2(5120, 2048)=682 diff -0.00 atan2(5120, 3072)=59.04 iatan2(5120, 3072)=589 diff 0.14 atan2(5120, 4096)=51.34 iatan2(5120, 4096)=517 diff -0.36 atan2(5120, 5120)=45.00 iatan2(5120, 5120)=449 diff 0.10 atan2(5120, 6144)=39.81 iatan2(5120, 6144)=398 diff 0.01 atan2(5120, 7168)=35.54 iatan2(5120, 7168)=364 diff -0.86 atan2(5120, 8192)=32.01 iatan2(5120, 8192)=329 diff -0.89 atan2(6144, 0)=90.00 iatan2(6144, 0)=899 diff 0.10 atan2(6144, 1024)=80.54 iatan2(6144, 1024)=814 diff -0.86 atan2(6144, 2048)=71.57 iatan2(6144, 2048)=724 diff -0.83 atan2(6144, 3072)=63.43 iatan2(6144, 3072)=633 diff 0.13 atan2(6144, 4096)=56.31 iatan2(6144, 4096)=562 diff 0.11 atan2(6144, 5120)=50.19 iatan2(6144, 5120)=502 diff -0.01 atan2(6144, 6144)=45.00 iatan2(6144, 6144)=449 diff 0.10 atan2(6144, 7168)=40.60 iatan2(6144, 7168)=405 diff 0.10 atan2(6144, 8192)=36.87 iatan2(6144, 8192)=370 diff -0.13 atan2(7168, 0)=90.00 iatan2(7168, 0)=899 diff 0.10 atan2(7168, 1024)=81.87 iatan2(7168, 1024)=820 diff -0.13 atan2(7168, 2048)=74.05 iatan2(7168, 2048)=741 diff -0.05 atan2(7168, 3072)=66.80 iatan2(7168, 3072)=666 diff 0.20 atan2(7168, 4096)=60.26 iatan2(7168, 4096)=602 diff 0.06 atan2(7168, 5120)=54.46 iatan2(7168, 5120)=545 diff -0.04 atan2(7168, 6144)=49.40 iatan2(7168, 6144)=493 diff 0.10 atan2(7168, 7168)=45.00 iatan2(7168, 7168)=449 diff 0.10 atan2(7168, 8192)=41.19 iatan2(7168, 8192)=411 diff 0.09 atan2(8192, 0)=90.00 iatan2(8192, 0)=899 diff 0.10 atan2(8192, 1024)=82.87 iatan2(8192, 1024)=828 diff 0.07 atan2(8192, 2048)=75.96 iatan2(8192, 2048)=759 diff 0.06 atan2(8192, 3072)=69.44 iatan2(8192, 3072)=693 diff 0.14 atan2(8192, 4096)=63.43 iatan2(8192, 4096)=633 diff 0.13 atan2(8192, 5120)=57.99 iatan2(8192, 5120)=581 diff -0.11 atan2(8192, 6144)=53.13 iatan2(8192, 6144)=534 diff -0.27 atan2(8192, 7168)=48.81 iatan2(8192, 7168)=489 diff -0.09 atan2(8192, 8192)=45.00 iatan2(8192, 8192)=449 diff 0.10
12/21/2016 at 16:20 •
Since the flu season began, I've been lying in bed sick quite some time. While I don't recommend doing coding with a fever (takes way too much time to track down the trivial mistakes you make), you do have some free time to explore some coding ideas that you didn't bother with before. One of such things on my to do list is rewriting Tote's inverse kinematics code to use only integer math, and I found a marvelous family of algorithms that can let me do it.
If you look at my explanation of Tote's inverse kinematics at http://tote.readthedocs.io/en/latest/ik.html, you will see that I'm using two trigonometric functions (actually inverse trigonometric functions) in there: atan2 and acos. They both return an angle -- in the case of the standard library functions, in form of a number between -PI and PI (or was it 0 and 2PI? I can't remember). That's a pretty arbitrary range, that I have to then convert into servo pulse width in the range between 600 and 2400µs. Wouldn't it me great if they instead returned integers from 0 to 1800, so that I could use them for the servo pulse width directly?
But how are such trigonometric functions calculated? There are several ways. You can approximate them with a polynomial, using a so-called Taylor series. You can also have a lookup table, with some interpolation for the values in between. But both of those approaches involve quite a lot of multiplications and divisions, and possibly floating point (or fixed point) numbers. Which is slow on a microcontroller such as the one used in Tote, not to mention a lot of code being generated (especially for the lookup tables). Fortunately there are the CORDIC algorithms, which involve only a lookup in a small table, some additions and some bit shifts. And of course you do it all on integers. Plus, you have very good control over the accuracy -- the more iterations of the algorithm you do, the better results you get.
How does it work? The heart of the algorithm is a small mathematical trick that lets you rotate a point (x, y) around the center of the coordinate system (0, 0) by a fixed angle using just additions and bit shifts, provided you know the arcus tangent value of that fixed angle. So you make a lookup table with a dozen values for 45°, 22.5°, 11.25°, 5.625°, and so on (each angle half of the previous one), and you do a binary search for your value.
Let's say you want to calculate cos(a). Imagine a length 1 line starting at (0, 0) and going to (x, y), with the angle between the x axis and the line being a. Then the value we are looking for is x. How do we find x? We will start with a line at angle 0° and coordinates (1, 0), and rotate it (using our additions and shifts) by 45° one way or the other, depending if our a is larger or smaller than 0. We will get some point (x1, y1) this way. Then we will rotate it again, by 22.5°, one way or the other depending on where the angle a is compared to our current angle. And we will repeat that, rotating by a smaller angle each time, until we get close enough to out angle a. At that point we have calculated our cos(a) (and also sin(a) at the same time).
Calculating the inverse trigonometric functions is similar, except we start with the line at (x, y), and try to rotate it to be as close to (1, 0) as possible, keeping track of how much we have rotated it so far. Once we got close enough to (1, 0), the total angle is our answer. Simple.
All that is left for me is to actually write some code, test it, tune it to use the smallest types possible and to work with enough accuracy for my particular use case, and put that code in Tote. I will let you know when that happens, but first I need to get over this flu.
12/07/2016 at 20:47 •
I've been asked for a Tote kit for a Christmas preset by a friend, and I realized I no longer have any version 4 boards. So I had to go and order some. But if I'm ordering boards anyways, why not make some improvements here and there? So here's a version 5.
You can see the board is much simpler now. It's basically just the servos, the battery, the pro mini, power switch and ir sensor. There are still the optional battery monitoring, piezo, distance sensor and extra capacitor, but by default they are not used. I also switched some pins around, so now using the serial pins for servos -- but all the analog pins are free, and broken out close to each of the legs. That should make it easier to use them for sensors.
There is also a new step-by-step assembly tutorial for this version at http://tote.readthedocs.io/en/latest/assembly_v5.html and slightly modified code at https://bitbucket.org/thesheep/tote/src/tip/v5.
And I still have the other 9 boards to give away.
Oh, right and a DirtyPCB link: http://dirtypcbs.com/store/user/preview/1154
11/10/2016 at 11:09 •
So, today I hotglued the lenses with the LEDs, updated the software to let me switch the LEDs on and off, added a piezo to the robot, so it makes sounds, and painted some red highlights on the legs. The end result:
And here's a short video:
11/09/2016 at 21:30 •
The winter is coming, and my robots need some maintenance -- after a year of traveling to various conferences and fairs, they accumulated a number of injuries. It's also a good idea to recharge the lipo batteries once in a while.
I started repairing the robots, replacing broken servos, tuning them, etc. -- and at some point I realized that they actually look pretty drab. Just a bunch of wires and servos, really. Of course, the idea was to make them as simple and easy to make as possible, so that's just expected, but still they don't look like something you would actually want to have. That's when I decided to take one of the prototypes (incidentally, the one that I used for proprioception experiments), and make a chassis for it, to make it look a little bit better.
So I went to the Internets and started to look through concept art of various robots. I'm quite surprised and saddened by how many of those are simply "a human in suit with a weird helmet". Oh well. Finally, I found one drawn by Paul Denton that fits Tote well and should be simple enough to make:
It's a bit dark and gritty, but that's even better -- any mistakes I make will not be as visible. So I started with a plastic box -- from a set of toy blocks for kids. Of course I started by cutting the corners:
Then I removed the legs from the robot, and installed the PCB inside the box:
I had to cur the sides of the box, and also the "ears" on the servos -- to make them fit properly without colliding with the box or with themselves. Once I was happy with the shape, I hot-glued the PCB securely in place and started painting. I'm using acrylic paints for painting tabletop battle miniatures. It sticks pretty well to plastic.
Once I had the base coat ready and it all dried, I started to dry-brush some of the wear and old paint on it, then dry-brushed the whole thing with metallic paint, to make it look like beaten metal.
Next, I had to do something with the wires. They are way too long, there is not enough space inside to hide them, and they are the wrong color. After some deliberation, I decided to just cut them to size:
And then I also painted them black. Some mor dry-brushing, and it's almost ready. I also made a hole at the top for the IR sensor for the remote to stick out.
Next, I worked on the eyes. I found some plastic lenses for LEDs in my drawer, and some red LEDs:
A bit of glue to secure the LEDs in place, some more to glue the lenses into the eyes, and some resistors and wires, and it's almost ready. Now I just need to wait for the glue to set...
01/29/2016 at 12:46 •
A lot has happened in the recent time for the hobbyist community, and I'm currently wondering where I want to take this project. Here's some random rambling on the subject, just to clear it out of my head.
- A Raspberry Pi Zero was released, and it's small and cheap enough to fit in Tote and provide some more advanced features, like a Python interpreter and possibly w WiFi camera. I forked #Tote Zero to explore that possibility, but it does makes things more complicated. An operating system, the need to shut it down cleanly, the need to keep it updated and properly configured, is a pain. Not to mention the booting time. Powering the Raspberry Pi is also much more involved than with Arduino -- I have to use a 2S battery, which needs a professional charger with balancing.
- Batteries. While it's easy to get a LiPo battery from an old cellphone or similar device, and there are lots of LiPo batteries available in shops for all those quadcopters, the technology is kinda tricky. They are not as safe as I would like, and you can damage them by over-discharging, so I need the voltage monitoring circuitry. Switching to standard NiCd or NiMH rechargeable AAA batteries seems like a good alternative. They are much heavier, but Tote can handle that. I will do some experiments in the near future.
- TV remote. This is the easiest and cheapest way to get remote control, so that's why I used it, but now I'm beginning to have my doubts. It turns Tote into a toy and discourages tinkering. It also requires some work if you have a different remote than mine -- you have to change all the key codes. And it's not really that great for precise control. On the other hand, bluetooth and WiFi both have some great solutions.
- Sensors. This is another thing that keeps Tote in the remote-controlled toy category. It needs to have more sensors by default. I have already found switches for the feet, and probably will make that standard. Unfortunately the popular and cheap distance sensors out there all require 5V to work properly, and the 3.3V versions are much more expensive, so I think I can't have them by default. Same for inertial sensors -- a good module with proper filtering simply costs too much.
- Micropython. I've tried multiple times to make Tote programmable in Python, and all of them turned to be sub-optimal -- either too expensive or too limiting. But there is a good chance that the ESP8266 port of Micropython will become much more usable, thanks to the Kickstarter campaign to fund its development. I'm still not sure there will be enough memory to handle everything I want, but it's certainly very exciting for me. Since the ESP8266 only has about 9 usable GPIO pins on it, and I need to control 12 servos, I would probably still keep the Arduino and offload the leg inverse kinematics calculations to it. I'm torn between this and the Pi Zero.
- Force feedback and compliant motion. This is a very interesting topic, and it makes the robot much more interesting, but with the current design I simply don't have enough analog pins, and their precision is also not so great. Thinking about adding some external ADC modules over I²C -- they are not very expensive. Then I would need to decide whether to measure the servo position (easy, not that useful) or the force (hacky, hard, much more interesting).
- Community. Right now I know about about 4 people other than me that have built a robot more or less inspired by Tote. As far as I know they do not communicate with each other and do not share experiences or ideas. I suppose I could do a lot better in this area.
- Open MV. I should get it in a few weeks, and I'm definitely going to try and put it on Tote or any of my other robots. But it's too expensive to be a default.