Elecrow has made both the PCBs and the laser-cut parts, and they have sent it Monday last week. Unfortunately, it seems that DHL has stopped its operations for some reason, because the package is still in "shipment information received" state after 7 days. Because of that I still have nothing to show, maybe except the photo I got from Elecrow when they sent it:
So I spent the weeked mucking about designing PCBs and throwing new features at them, but if I am supposed to ever finish this project, I need to do some actual work on it. So today I tried to stay focused and do the actual steps that need doing. First, a feather-compatible robot would be great, but it's also complex. At first the only thing I will need is I2C, so let's just make a minimal PCB with just that broken out.
Second, all this is pointless if I can't control the servos. So I need to make sure the pins I connected to servo signals actually can do PWM all at once. The easiest way to do it is to just quickly compile a custom CircuitPython firmware with those pins made available, and try it on a Trinket M0. That's exactly what I did, and of course it didn't work. I had to swap two of the eight pins to make them use different timers, so that they can be used all at once. Of course that made the layout a bit less pretty but that's fine.
Once I have figured out which pins will work, I also fixed the feather-compatible schematic. That took considerably more work, since I didn't have any free pins I could switch to, and there were certain requirements for functions available on certain pins. In the end I think I got it, though, so that PCB is fixed as well.
Finally, I need designs for the leg pieces for that small board. Laser-cutting is considerably cheaper than PCBs, and now that I can order it from Elecrow alongside the PCBs, it doesn't make it much more complex. So I had to re-do the legs, but since I want to use the same code, I wanted to keep the same dimensions. So some reverse-engineering of the PCB designs was necessary:
Once I had all the dimensions and shapes figured out, I just had to arrange all the parts on a 10x10cm sheet:
Now both versions of the robot PCB, the Fluff M0 board and the laser-cut parts are on order — the work will continue in a few weeks when they arrive, and in the mean time maybe I can focus long enough to program the walking code.
I have spent the whole Sunday re-doing the PCB design, and then adding battery protection, charging and a speaker with amplifier. It looks like this now:
And then I realized that the puny SAMD21 is not going to have enough memory to make use of this — at the very least I will need external flash. And I might as well switch to the SAMD51 at this point, since it's not that much more expensive. That also gives me more pins, so I can have a proper feather pinout plus all the servos and plus some extra stuff. However, I will need to completely re-do the design for that, so it will probably wait until the next weekend.
I still have no strength to sit down and program a proper gait, but I keep thinking about the mechanical design and having ideas. One thing I'm going to need is some kind of an expansion socket on the front part of the robot, so that I can connect different kinds of sensors, displays, faces, etc. I could simply just have a pin header with all the unused pins broken out randomly, but that's not very convenient. I could have several headers, to match several of the modules I want to be able to connect, but that gets complex fast. Or I could use some kind of a standard footprint — for example the one for Adafruit Feather, so that I can connect FeatherWings to it. But here is a small problem: the Feather M0 uses a larger SAMD21 chip than I was planning to use — does my chip have enough pins to re-create the pinout?
So I went to Adafruit's website, grabbed the schematic they published, and started working:
The answer is yes, you can do it, with only 7 pins that are not available on this chip, but easily replaced with other pins. And you still have 3 pins free!
Unfortunately, I need at least 8 additional pins to control the servos, and they have to be timer-capable pins to do PWM. So either I switch to a chip with more pins (and at this point it would probably be SAMD51, because I already have it in my drawer), or I use some of the pins that are unlikely to be used by the FeatherWings that I need — in this case that would be the analog pins. I would leave the A0 (because it also has DAC), and re-reoute A1-A5 to the servos, which together with the 3 extra pins should be enough. I would need to do some experimenting to see if all of those pins are PWM-capable, and probably swap some of them around if they are not — something that requires more effort than I am ready to spend right now.
Second thing I was thinking about is the mechanical design. I think I figured out how to best attach the servos to the main body of the robot, without needing to solder loops of paperclip wire to the PCB. See those four slots in the PCB? You just need small horizontal bars that go inside them, with holes for the servo screws. They will push against the outer edge of the slots, and the servos will push against each other, and that should give you a pretty solid attachment.
And the next thing — I originally designed this robot to be just a single piece of PCB, that you just break to get all the parts for the legs and body. This way you don't need access to a laser cutter or a 3D printer. But after my experiences with #PewPew M4 I discovered that it is very easy to order your laser-cut parts together with the PCB, and they are so much cheaper than the PCB is! They also are thicker and look better, so there is really no point in using PCB for construction anymore. That brings me to redesigning the legs and the body to be laser-cut, and the PCB to be as small as possible and attached on top.
After several weeks of severe brain underperformance, I finally managed to get the inverse kinematics code for this robot right — so now I can move its legs properly. This encouraged me to work on it some more, so I went ahead and re-arranged the servos to the configuration I want:
Of course the PCB on top will be re-designed and will take the place of the yellow PCB in between the servos, with the battery on the back, and maybe a sensor and/or some LEDs on the front. The connectors for the servos will be at the bottom, so there will be fewer visible cables as well.
The servos are bolted to loops made out of paperclips soldered into the PCB, but I'm not entirely sure how I will solve this in the final version.
It's been a while since I worked on this — I've been busy with #PewPew M4, though I did update the #SpiderWing and test the battery protection circuit there. But I never finished the SAMD51 version of the PCB for Kubik M4, and it has been on the back burner.
Most recently, however, I realized something: the Kubik M0 PCB doesn't have to be a failure after all. Well, of course, if I wasn't terribly lazy I could write a servo library for the CircuitPython that handles 12 servos with a timer interrupt and use that — the microcontroller is easily fast enough to do it — but that would require effort. But I thought about something else: I have a version of the walking quadruped that doesn't need 12 servos — #Katka, a mammalian robot only needs 8. Sure, turning is a bit of a challenge, but I could totally re-use the Kubik M0 PCB to build a Katka M0. So I went ahead and did it:
The four hip servos went away, and I instead attached the knee servos directly to the PCB, making them the new hips. I think I will try to program it to walk in the configuration shown on the photo, even though it could also easily walk in a more mammal-like posture, with the knees below the hips. But I want it too still look a bit like a spider or insect, so I will go with this.
Of course I can't re-use the code I had for Kubik anymore, so I will also get to re-write the whole walking thing in a cleaner way, possibly using async functions. The inverse kinematics should now be much simplified, and also the cost of the whole device dropped by roughly 1/4 with the removal of the servos. If I can find a reasonable way of turning, then I'm going to go forward with this (re-designing the PCB for easier attaching the servos in this configuration, and adding the battery protection I tested with the Spiderwing).
So I started to work on the new PCB, using a QFN48 foorprint for the SAMD51G. Of course the footprint I made earlier for the IS31FL3733 chip was inexplicably broken — as soon as I started editing the pin descriptions it started doing really weird stuff. So I re-did it, together with a proper schematic image and all that. Then I started with the PCB I re-did recently for the #D1 Mini Tote, only replaced the PCA9685 with the SAMD51G:
Yes, it's a mess for now. Ideally, I will use the same headers as for the D1 Mini, so that I will be able to use all the D1 Mini shields with this robot — including the #Accelerometer Shield for D1 Mini I made recently (that's one reason why I removed the accelerometer from the PCB, actually). However, I still don't know which combination of pins will have the correct set of timers for making all those PWM outputs. But I'm confident that such a set of pins exists, because of an experiment I made with an ItsyBitsy M4:
import board import pulseio pins = [ 'D7', 'A1', 'D0', 'D1', 'D2', 'D4', 'D5', 'D9', 'SCL', 'D10', 'D11', 'D12', 'D13', ] pwms =  for name in pins: pin = getattr(board, name) print(name) pwms.append(pulseio.PWMOut(pin, frequency=50))
So yeah, I can have at least 13 PWM outputs — I'm sure I can find a set of pins that will work. Whether they will be easy to route is another question, but I have a lot of space and as many vias, as I need. Also note, that on the current PCB I actually have 16 servo sockets, not 12 — ultimately there will be 4 fewer.
I will probably also add a flash chip and that speaker with an amp — this way I can put all the turret voices from Portal on it.
I compiled a custom CircuitPython firmware with all the pins exposed, and ran a simple program looking for any combination of pins that would give me 12 PWM outputs:
for permutation in permutations(pins): pwms =  for pin in permutation: try: pwms.append(pulseio.PWMOut(pin, frequency=50)) except (RuntimeError, ValueError): pass if len(pwms) > 10: print(pwms) for pwm in pwms: pwm.deinit()
Yes, I know, I could have checked the datasheet for timers instead, but this is easier and makes more more certain.
That's a lot of permutations to check, so it took some time, but ultimately it came up empty. There is no permutation that would give me more than 10 PWM outputs on the SAMD21E18A chip. So what other options do I have now?
I could use a SAMD21G18A that has 38 GPIO pins — I'm sure they come with some extra timers that would enable a few extra PWMs. But the SAMD21E18A costs $2.38 in singles, while SAMD21G18A costs $3.47. That increase in price wouldn't be that bad by itself, however, for $4.01 I can have a SAMD51G19A instead, and a PCA9685 costs a dollar.
So now I have several options:
But it's not just about the price, is it? The SAMD51 is a massively more powerful microcontroller, with *much* more RAM, faster clock and more flash. Also hardware floating point operations and a bunch of other stuff. And that is for just $2 more. I really think that it's the best option. Besides, I've been wanting to make a board with that microcontroller for a while, but since #µGame Turbo is on hold, I didn't really have a chance. On top of that, I have one already in my drawer, so no need to wait for parts (though I will still need to wait for the PCB).
It turns out there have been some bugs in CircuitPython's pulseio module, related to how it selected what timer/channel to use for PWM for each of the pins. Long story short, it would sometimes re-use the channels that were already in use, resulting in those pins sharing duty cycle — you change it on one of them, it changes on the other as well. Obviously that's not good for us. The good news is that the bugs have been all fixed now. The bad news is that it's not possible anymore to have a PWMOut created for all the pins I'm using for servos at once — it was possible only because of that bug...
That means I need to redesign the PCB to use a set of 12 pins for the servos that can have PWMOut created for them all at once. To do that, I will need to do more testing to determine which pins I can use, and there is always a possibility that I don't find such pins — in which case I will need to switch to a bigger package, and possibly also a SAMD51 chip.
I also need to rethink the battery charging circuit — I want to keep the robot off while it's charging. Would also be nice to add that flash memory chip, for extra filesystem space for all the files.
I think I will drop the accelerometer in the process, because it turns out to not be that useful. I will also give up on the idea of keeping the top of the PCB clean and fitting all the components inside the hole in the battery holder — that was an interesting, but ultimately pointless challenge. I still want to have all SMD parts on one side of the board, though, because that makes assembly easier and cheaper, so they will probably all go on the top, with only THT parts on the bottom.
I had a bit of a break with this project, while I worked on other projects and dealt with some life stuff, but I very much still want to work on it. Obviously the very next step that needs to be done is to program the robot to do actual walking, at least at the level of #Tote, and then possibly make use of the accelerometer and the leg switches. I assume that this will actually take me some time. In the mean time, CircuitPython is being developed further and ported to the NRF52 chip, growing bluetooth support along the way, so the long-term plan is to switch to NRF52 from the SAMD21 chip. That will probably involve a redesign of the extension connector as well, so I don't think I will be working on any extensions until that happens.
Once the connector design is finalized, it will be time to look at possible extensions and the sensors to include on them. I want to have an OpenMV adapter, and also a simple "face" with distance sensors on it.