I've been working on a slightly different way to handle the main loop() in Nybble's code. Basically the idea is to move control of the main loop off the nyboard and onto the raspberry pi, so that we're not quite so constrained by the amount of code space on the nyboard. I wanted to reduce the functionality of the arduino code to only doing I/O, and let the pi handle all the smarts.
To do that, I've been working on this fork: https://github.com/regularfry/OpenCat/tree/acy-data-loop
If you have a look, you'll notice a few things going on in OpenCat.ino. First, the guts of the loop() function are mostly gone, replaced with the excellent protothreads suggestion from @Gero . I've nicked the ultrasound implementation and moved getYPR() into a background thread. checkBodyMotion doesn't exist any more; I want anything that smart happening off-board.
There's a new file called interpreter.h, which is a different take on the serial protocol. Rather than stay with an ad-hoc syntax, I've implemented a very simple FORTH-syntax repl; I haven't got as far as allowing loops or user-defined functions yet, and I'm not sure there's enough RAM to do so, but it's on my list to try. What that all means is that if you run it, on the serial line you'll see this:
* Start *
Initialize I2C
Connect MPU6050
Test connection
MPU successful
Initialize DMP
Checking hardware revision...
Revision @ user[16][6] = A5
Resetting memory bank selection to 0...
1148 -61 -33 12
Enable DMP
Enable interrupt
DMP ready!
* Assigning 4 skill addresses...
1
2
3
3
3
3
3
3
3
Finished!
>
That is, there's the usual boot and a mildly tweaked setup() routine, then it drops you straight to a prompt. From there, with the serial line set to "Newline", you can run commands like:
0 8 m
That is the equivalent of "m 8 0" in the conventional serial syntax. Or:
0 8 m 0 12 m 0 9 m 0 13 m
That zeros the front two legs in a single command. Or, shorter:
0 0 0 leg 0 0 1 leg
which does the same thing. There's also a "pose" and a "legPose" command, which set either all the motors or just the walking motors all at once:
-30 -80 -45 0 -3 -3 3 3 60 60 -60 -60 -45 -45 45 45 pose
That would be the equivalent of the existing "rest" command. After each of these, you get dropped back to a "> " prompt.
If you want to read Nybble's sensor state, you've got the "p" command:
> p
t 4710
b 273.00
g 0.09 -0.08 0.99
u 6.05
m 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256 256
--
>
What that's giving you is the timestamp, battery voltage, gravity vector, ultrasound range, and motor angles (with 256 being used as an "off" signal in this case). It'll also give you raw IR data if it picks a signal up.
With just the gyro in the loop, before I switched to protothreads, I could happily run a 20Hz update loop, with python on the host requesting state, doing calculations, and issuing motor commands, with about 20ms to spare per cycle. I haven't done any timing yet, but I think I'm right in saying that protothreads make this safe with ultrasound and the buzzer thrown in, and I might even be able to go a bit faster. At the moment, the motor updates are happening in the same protothread as the serial processing, and if I separate them out I can probably run the motor updates at a higher rate to smooth them out and get some interpolation back. I need to double-check that I'm not going to get into trouble with stack usage, though.
The downside of all this is that I've pretty much thrown out all the code around instincts, behaviours, and gaits. They should be easy enough to add back in on the python side - after all, it's just a matter of putting the right commands together from the data in InstinctNybble.h and feeding them over the serial line - but that's probably not next on my list; I'm more interested in getting to a walking cycle that's less pre-canned and more calculated on the fly, which is the whole reason for bothering with any of this. I'm pretty sure we can get to a dynamically stable trotting gait with a following wind (although not hopping, I don't think the motors will take it). I've got him balancing (very, very shonky feedback control works disconcertingly well), but I managed to overload an MG90D doing knee duty in the face of some rather over-enthusiastic gain factors and have been waiting for more servos in the post for the last couple of days.
Have a poke, have a play, let me know what you think. I'll commit some example python that uses this protocol in the next couple of days, and *possibly* some erlang or elixir if I get enough time over the weekend. Right now I'm developing all that on the pi over ssh, which is a lovely way of working.
Oh, one other thing - this almost certainly breaks Bittle in horrible ways. Looking at the shared code I suspect the two could be brought into line fairly easily if there was interest, but I've not got one to check against.
Aha~ I think we can discuss the platform and devices.
When I joined the Petoi, the NyBoard V0_2 was under mass production and V0_3 was evaluating. And I'm trying to port the OpenCat to the ESP32 platform.
But I think there're some disadvantages of NyBoard we're selling. After discussing with RZ, we re-designed the whole NyBoard V0 to V1.
We removed the Nyboard overclocked bootloader, change it to UNO's bootloader. It's much easier to use. You can use NyBoard V1 as an ordinary Arduino development board.
Safety enhancement. 3-way independent power sources. Anti-reverse circuits, diodes and fuses are added.
Scalability. We added 4 grove sockets and 2.54mm pins. We added LEDs. We added WiFi and Bluetooth modules. We want to make it more fun.
Some improvements are been cancelled:
For more hardware resources, use ATMega328PB and ATMega4809 instead of ATMega328PA. There's none official bootloader support.
Bluetooth/USB combo modules. Not stable and too many switches.
Still in evaluation:
STM32 version. We're optimizing and integrating libraries.
ATsamd21 (Arduino M0), waiting for a stable USB-CDC driver for the Arduino.
@Alex Young Thanks for your work!
I think you can try our WiFi module as the intelligence processor (we call it application processor, AP). 160MHz/80KB RAM/4MB Flash is faster than the ATMega328P. Or you can transfer data to Pi with a WiFi connection.
For the flash storage limit, we cannot add an extra serial protocol to NyBoard V1. We're still optimizing the code to make room for the protocol in HEX like this:
| packet header | sender | receiver | payload | CRC |.
But it's not easy to understand by beginners. So we still use protocols in chars.
A host program developed with Qt that controls the NyBoard has nearly finished development and under testing.
@Gero We just finished mass production and testing BiBoard. A little late because of the Chinese new year and lack of chips. Now they are on the way to the backers! We also re-designed the BiBoard (not the same as the green one). Adding a strong 5V-5A max power to support Raspberry Pi 4 or further model.
A secret "sandwich" model is in our progress.
Maybe is the Pi compute module with EMMC and the Pi pico.
That's where I got to - servos being in the middle really doesn't help. I'm trying to put together some resistive pads to attach to the feet so you can measure the down-force, that would at least give you something to work with. The other place to look would be getting at the motor current *somehow*.
I'll take a look at the python, thanks for that. I'm not getting as much time on this as I'd like, but we'll get there 😀
To answer your question about feedback control, all I've done as a sort of proof of concept to show anything was possible at all is to take the gravity vector and use it to change leg lengths, in a very approximate way - Nybble balances on a tilting book up to a good 30 degrees off-horizontal just by using the components of the gravity vector away from vertical along the x and y axes *directly* as error signals, you don't even need to do any trig. Just a gain factor of about 0.05 so the movements aren't too violent. That does limit the speed he can react at, so it's shonky as hell, but like I say - proof of concept :-)
I'm still working on it, but aiming at a Raibert-style trot. The lack of shoulder roll, direct torque control, or foot sensors makes it a bit of a challenge, so I'm having to go back to basics a little and work some of the maths out from first principles.
The good thing about this sort of gait is that the calculations are really simple. The execution time is dominated by waiting for IO on the nyboard, you don't need very much CPU grunt at all. I'm sure it *could* be done on the biboard, but I actually prefer having a linux distro mounted on Nybble for a number of reasons, not least that I'm far more comfortable there and if I do want to strap a camera on too, I know exactly what I'm doing hardware and software-wise. Boot time is the one downside, but once I've got something that's worth packaging up I've got buildroot as an option.
I'm also quite keen to give erlang a try at some point, and I don't think BEAM's been ported to ESP32.
Energy consumption won't be a big problem because a single servo could consume as much energy as a Pi. So we designed the system to support 5A power. The current configuration only consumes 3A at max speed. However, the BiBoard doesn't have a direct socket to plug the Pi. It's designed to take more wireless communication than physical connection.
Could you tell me a little bit more about your feedback control implementation and the dynamic gait generation you mentioned?
I noticed, that @Rongzhong Li is working on an ESP32-based board BiBoard, which might be superior concerning weight and energy consumption in comparison to an additional Raspberry Pi. Do you think that BiBoard v0 might already suffice for your feedback control idea?