Self balancing robot
Re: Self balancing robot
Cool build!
Re: Self balancing robot
@pythoncoder. Very impressive indeed, it is huge compared my version - it must hit the ground with a resounding clunk when balance fails
I am currently trying to reduce my wiring bird's nest by replacing breadboards with perfboard. The wifi control using an ESP8266 and mobile phone works well. I will update GitHub with this and incorporate your code suggestions when I clean it up.
I am currently trying to reduce my wiring bird's nest by replacing breadboards with perfboard. The wifi control using an ESP8266 and mobile phone works well. I will update GitHub with this and incorporate your code suggestions when I clean it up.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Self balancing robot
While I stand by my code suggestions I'm still working on the algorithm and maths: I'll comment further when I've come to a conclusion. I'm looking at solutions where the only nonlinear constraint is on motor speed but it's a work-in-progress
One physical change I intend to make is to fit some kind of buffers so that it hits the ground with less of a clunk! The battery at the top is actually a six volt sealed lead acid one, so it's heavy. These are cheap and, as we've already discussed, weight high up is an asset. The remote control I have in mind is a pybard with an NRF24L01 radio. I was actually trying to figure out how to mount a little joystick when I realised I didn't need one. Why not use the Pyboard's accelerometer and just tilt the thing to achieve control? The biggest thing in the remote will be the 9V battery.
My work on the algorithm is to answer the questions of whether it can be further simplified and how best to achieve concurrency: it would be nice to have the fast control loop running as a separate process, either using cooperative multi-threading or by having it run as a timer callback. Concurrency might make it easier to enhance the robot to do other things like moving to specific locations or handling sensors.
One physical change I intend to make is to fit some kind of buffers so that it hits the ground with less of a clunk! The battery at the top is actually a six volt sealed lead acid one, so it's heavy. These are cheap and, as we've already discussed, weight high up is an asset. The remote control I have in mind is a pybard with an NRF24L01 radio. I was actually trying to figure out how to mount a little joystick when I realised I didn't need one. Why not use the Pyboard's accelerometer and just tilt the thing to achieve control? The biggest thing in the remote will be the 9V battery.
My work on the algorithm is to answer the questions of whether it can be further simplified and how best to achieve concurrency: it would be nice to have the fast control loop running as a separate process, either using cooperative multi-threading or by having it run as a timer callback. Concurrency might make it easier to enhance the robot to do other things like moving to specific locations or handling sensors.
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Self balancing robot
I have now updated the code at:
https://github.com/jeffmer/micropython-upybbot
I have included the Arduino sketch that implements a UDP server on the ESP8266 for OSC messages and the template for the TouchOSC app on my iPhone used as the controller. This follows the B_ROBOT approach. The controller implements two approaches - faders or buttons - the operations should be obvious from the screendumps below:
@pythoncoder. I agree that having a concurrent implementation would be best. The issue is that to get real-time response a pre-emptive scheduler is needed rather than the cooperative scheduling that can be achieved using yield. As you suggest, the only plausible approach is to use a timer driven interrupt service routine and forego floats.
BTW. The poll routine that gets wifi messages in the revised code takes approximately 1.5ms if there is a message to process so it is within the 5ms budget.
https://github.com/jeffmer/micropython-upybbot
I have included the Arduino sketch that implements a UDP server on the ESP8266 for OSC messages and the template for the TouchOSC app on my iPhone used as the controller. This follows the B_ROBOT approach. The controller implements two approaches - faders or buttons - the operations should be obvious from the screendumps below:
@pythoncoder. I agree that having a concurrent implementation would be best. The issue is that to get real-time response a pre-emptive scheduler is needed rather than the cooperative scheduling that can be achieved using yield. As you suggest, the only plausible approach is to use a timer driven interrupt service routine and forego floats.
BTW. The poll routine that gets wifi messages in the revised code takes approximately 1.5ms if there is a message to process so it is within the 5ms budget.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Self balancing robot
Very neat! I've yet to experiment with writing tablet or phone apps.
As for concurrency, it's worth bearing in mind that a simple loop like ours can be interrupted by a garbage collection, which on my measurements takes 3-4mS. The only way to get a truly deterministic loop time is to use a timer interrupt.
I think that, with the maths modified to take account of loop delay as I mentioned earlier, the 'bot can be made more tolerant of loop time which might open up the possibility of using cooperative scheduling. However until I get a better level of stability any experiments are limited in their usefulness. At present I'm having trouble combining a good response to the remote with good stability. It's stable insamuch as it doesn't fall over, but its does "hunt" more than I'd like (and more than yours does).
I have two project branches, one with and the other without the speed filter and I'm still unconvinced that the filtered version is any easier to optimise. But comparing different outcomes is so subjective: getting these things to run really well isn't easy
As for concurrency, it's worth bearing in mind that a simple loop like ours can be interrupted by a garbage collection, which on my measurements takes 3-4mS. The only way to get a truly deterministic loop time is to use a timer interrupt.
I think that, with the maths modified to take account of loop delay as I mentioned earlier, the 'bot can be made more tolerant of loop time which might open up the possibility of using cooperative scheduling. However until I get a better level of stability any experiments are limited in their usefulness. At present I'm having trouble combining a good response to the remote with good stability. It's stable insamuch as it doesn't fall over, but its does "hunt" more than I'd like (and more than yours does).
I have two project branches, one with and the other without the speed filter and I'm still unconvinced that the filtered version is any easier to optimise. But comparing different outcomes is so subjective: getting these things to run really well isn't easy
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Self balancing robot
I beg to differ. real-time does not require pre-emption. This seems to be common misconception. I've written lots of non pre-emptive real-time systems. And in fact, its often much more efficient to use non pre-emptive systems.jeffm wrote:@pythoncoder. I agree that having a concurrent implementation would be best. The issue is that to get real-time response a pre-emptive scheduler is needed rather than the cooperative scheduling that can be achieved using yield. As you suggest, the only plausible approach is to use a timer driven interrupt service routine and forego floats.
There are overheads required to using pre-emptive systems (often as much as 5%). Pre-emption can also cause performance problems in other ways, such as disrupting execution pipelines, messing up caches.
So I'm just trying to say that you do real-time perfectly well with pre-emption or without. In some circumstances, pre-emption makes real-time easier, and sometimes it doesn't.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Self balancing robot
@dhylands Agreed, a truly pre-emptive system requires serious programming skills and a good set of supporting primitives. Most of the systems I've encountered have limited true pre-emption in the form of interrupt handlers, with cooperative scheduling for the bulk of the code. The potential difficulty with control systems is where the core control loop is sufficiently time critical that it has to run in true real time - in MicroPython terms as a timer callback. As I'm sure you're aware, time delays can play hell with feedback systems.
My impression is that balancing robots don't fall into that category - but I won't consider the case proven until I have a better balancing robot The most challenging control system most users are likely to encounter is a multicopter: I wonder if the Pyboard is fast enough to stabilise one of those with the main loop running in a cooperative thread?
My impression is that balancing robots don't fall into that category - but I won't consider the case proven until I have a better balancing robot The most challenging control system most users are likely to encounter is a multicopter: I wonder if the Pyboard is fast enough to stabilise one of those with the main loop running in a cooperative thread?
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
Re: Self balancing robot
@dhylands Your comment really makes the point that the term real-time is hopelessly imprecise and I do apologise for this imprecision on my part. I was of course referring to the situation where there is a requirement to mix activities or tasks that require bounded response time to external events with tasks with potentially unbounded run times. In this situation, pre-emption is needed. I do however completely agree that cooperative scheduling is more efficient, for example in guaranteeing exclusive access to shared datastructures. I know of systems where the compiler or interpreter introduces potential rescheduling breaks - for example in loops so that maximum execution times are bounded - however this can also be inefficient.
@pythoncoder. I was wondering about the garbage collector - would it be best to disable automatic collection and explicitly call gc.collect() at the end of each balance loop?
@pythoncoder. I was wondering about the garbage collector - would it be best to disable automatic collection and explicitly call gc.collect() at the end of each balance loop?
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Re: Self balancing robot
@jeffm I think you may be on to something there. I wrote this script to test the idea:
The idea is to create and delete a 1024 element list every loop (doing a bit of maths just to prove it really is working) and examine the timings with different GC strategies. The outcome was as follows:
Auto GC: loop time varied from 439uS to 2011uS (when GC occurred)
GC every 20 cycles: 431 to 606uS
GC every 5 cycles: 431 to 493uS
GC every other loop: 431 to 457
So doing it each loop makes sense, potentially reducing GC time from over 1.5mS to 26uS. Remember to re-enable GC when you stop the robot if you're likely to want to run any other code on the Pyboard!
Code: Select all
import pyb
import gc
def gcalloc():
a = [0]*1024
a[pyb.rng()&0x3ff] = 1
res = a[275]
del(a)
return res
def test(gc_iterations = 0):
maxtime = 0
mintime =1000
sigma = 0
if gc_iterations:
gc.disable()
for n in range(100000):
tim = pyb.micros()
b = gcalloc()
sigma += b
t = pyb.micros() - tim
maxtime = max(maxtime, t)
mintime = min(mintime, t)
if gc_iterations and not n % gc_iterations:
gc.collect()
print(maxtime, mintime, sigma)
gc.enable() # For subsequent runs
Auto GC: loop time varied from 439uS to 2011uS (when GC occurred)
GC every 20 cycles: 431 to 606uS
GC every 5 cycles: 431 to 493uS
GC every other loop: 431 to 457
So doing it each loop makes sense, potentially reducing GC time from over 1.5mS to 26uS. Remember to re-enable GC when you stop the robot if you're likely to want to run any other code on the Pyboard!
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.
- pythoncoder
- Posts: 5956
- Joined: Fri Jul 18, 2014 8:01 am
- Location: UK
- Contact:
Quantifying stability
One instructive test I've tried is this. Before the start of the main loop I have
and in the loop:
This allows you to tweak the constants at the REPL, run the code, and check the excursions of speed and angle. It might be worth extracting the standard deviation of speed as well as the absolute maximum, but in principle it provides a way of measuring static stability rather than just sticking a wet finger in the air
Code: Select all
fangle = 0.0 # Angle from complementary filter
vmax = 0
fanglemax = 0
count = 0
Code: Select all
count+= 1
if count < 3000:
vmax = max(vmax,abs(fspeed))
fanglemax = max(fanglemax, abs(fangle))
elif count == 3000:
print(vmax, fanglemax)
Peter Hinch
Index to my micropython libraries.
Index to my micropython libraries.