PID Control Challenges(janismac.github.io) |
PID Control Challenges(janismac.github.io) |
The (spring loaded) inverted pendulum was one of the earliest analyzed models of legged locomotion.
Thats what all those self-balancing scooters are.
Both are useful.
Is the sample solution just hardcoded or is there some maths behind it to make it work from any location/initial speed?
function controlFunction(block)
{
let L = Math.floor;
let x = block.x;
// Use Collatz. L(x+½) is the closest integer.
return
-(L(x+0.5) % 2 === 0
? x/2 // Even, we chop it
: 3*x + 1 // Odd, we triple-plus-one it.
);
}
It's not very good, but it does beat or tie some of my earnest attempts to get below 8 seconds.Pretty neat website overall. Seems like I'll be wasting some time on it.
On the "Cruise Control Intro" challenge it's not made clear what the output of the controlFunction is. Am I returning a throttle position? A delta to the throttle position? Something else?
I didn't have any trouble until I got to "Ball on Platform: Balance" which seems to be multiple steps more difficult than the previous ones.
Don't get me wrong, I think this is really awesome! We are only talking about a few UI improvements to what is already an excellent resource.
This would probably not be a concern in this digital simulator, but such an error can pop up when trying the same thing out in real life.
See slide 17 here for a plot: https://www.slideserve.com/sibyl/finite-settling-time-design
https://backreaction.blogspot.com/2022/12/how-chaos-control-...
I actually made a similar thing based on writing your own autopilot for a Lunar Lander [1]. It's hard to make the difficulty increase linearly though. I like the use of different scenarios in this one.
function controlFunction(block)
{
const max_force=1000000000;
const margin=0.01;
const friction_comp=0.2;
if(block.x<-1-(margin/2))
return max_force*(1+friction_comp);
else if(block.x<-1.15*margin)
return -max_force;
else
return -block.x;
}The rest of the puzzles get pretty interesting, I shouldn't have just stopped on the first and spent all the time optimizing it.
If the author sees this thread it would be fun if you could disturb the dynamics with the mouse after completing one. I wanna watch the ball catching piston right the ball if I poke it.
@ajtulloch might be the world’s leading expert in making 100 billion bucks in 2 months with a device that can be built out of mechanical parts.
So in many, if not most, contemporary Information Retrieval (IR) problems, there is a total document set larger than could be explored on an interactive basis and so the data structures get laid out in such a way that with some probability north of a coin, you’ll find “better” documents in the “front” half. This is hand-waving a lot of detail away, so if you’d like me to go into some detail about multi-stage ranking, and compact posting lists and stuff I’m happy to do that in subsequent comment.
But it’s a useful fiction as a model and the key part is that there’s still “good” stuff in the “back” half: you’d like to consider everything if you had time.
A PID controller (again oversimplifying a bit) is charged with one primary task: given some observed quantity (temperature in a room) and some controlled quantity (how hard to run the AC), maintain the observed quantity as close to a target as possible via manipulating the controlled quantity.
If you hook one of these things up to an IR/search system (web search, friend search, eligible ads, you name it) where the observer quantity is e.g. the p95 or p99.9 latency of the retrieval, and the controlled quantity is how “deep” to go into the candidate set something magical happens: you always do something close to your best even as the macro load on the system varies.
That’s again a pretty oversimplified (to the point of minor technical inaccuracies) TLDR, but I think it makes the important point.
If you’d like more depth feel free to indicate that in a comment and I’ll do my best.
function controlFunction(block) { let x = 5; if (block.dx > 0) { x = block.dx; } if (block.T > 1.75) { return 0; } return 2 * x; }
function controlFunction(block)
{
const t = Math.round(block.T / 0.02);
return (t <= 10) ? +50
: (t <= 18) ? -50
: (t == 19) ? -22.4538198550841
: (t == 20) ? -27.5461801449159
: 0;
}
Misses the target by 6.1E-16 at an velocity of 6.3E-15. But yes, this should probably randomize the initial conditions or parameters like friction and gravity a bit so that you actually have to control the system.Beware: time flies past
function controlFunction(block) { return -500 * block.x -60 * block.dx; }
Unless your chip has a hardware floating point unit, you're stuck using software float operations. They're slower, though not extraordinarily so. But the main drawback is the floating point library can massively inflate your code size to the point that it no longer fits in available memory.
If you can get away with it, it's fine, but when you can't it's a huge problem.
nothing about real-life controllers
There are also many cases where floating point is the clear winner, but again, you should think about it and not just choose floating point reflexively because it seems easier. Its convenience makes it very easy to sweep errors under a rug, and they always come back to haunt you later.
Or it's more like, it's being used to fine tune the parameters of another search procedure? And in principle you could use a neural net rather than PID (that would encode a surface that matches the latency vs search depth profile that you want)
edit: just figured out those two are the same thing; the PID is optimizing the search depth for a given target latency
The number of documents (denoted as N) to search over consumes resources and increases the overall latency of the search infrastructure. However, the amount of traffic ebbs and flows. Under periods of lower traffic, we likely can increase N to provide good search results without violating latency constraints. Conversely, high traffic periods likely requires lower values of N.
Let's then approximate system strain by p99 (or p99.XXX) latency.
Solution:
Use a PID controller to set N as a function of latency (p99, p99.5, etc.) of the cluster. This leads to the outcome where N reduces when p99 latency starts to spike (resource starvation), and increases when p99 is low.
It's more exciting to calculate the dynamics if you need to be jerk limited.
echo "V fzvyrq gbb jura V yrnearq nobhg ebg13" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
I would be sure there's plenty of applications for PIDs in a game engine itself - a quick search turns up things like self-balancing physics objects, making game entities turn to follow a mouse pointer, and so on.
My reaction was a similar "Huh - makes sense".
It could be a moving enemy, flying robot or a spaceship, rotating gun turret, maybe even doors which need to be moved to desired position.
Even without physics engines PID controllers can be useful in games for making procedural animations. Having an object suddenly starting and stopping a movement doesn't look natural. It looks much nicer if initially an object slightly lags behind, slows down closer to target and maybe even slightly overshoots the target. It looks more natural because that's how things move in real life even non mechanical things. Try quickly swing a hand and then stopping it, you will see a little bit of overshoot/oscillation at the end.
PID controller isn't the only solution to the situations described above and sometimes it's an overkill. Sometimes you might just script or animate certain behavior. Sometimes you might use a simplified control model. Sometimes you might implement P, and intentionally or not achieve other components by adjusting physics object properties like friction (unfortunately you can't easily change physics properties in real world). With regards to animation example similar look can be achieved by directly animating it and any good animator will be familiar with things like ease in, ease out and overshoot, that's fine for static animations but games are interactive so it's nice if things react to player movements. Procedural animations can also be achieved by simply using the physics engine and letting things dangle, but that will probably be more computationally expensive than simple PID controller, also harder to constrain and prevent violent shaking in case of unexpected collisions with other world objects especially when some of them are manually animated.
Each approach has their own tradeoffs. And which one gets chosen will depend on the specific situation and skillset of people making the game.
There are couple of factors that make using a PID controller in games a bit easier compared to real life. In games you can usually directly read the exact positions and speeds of all objects, you can generate force out of thin air, you can generate unrealistic forces and if something goes wrong you can simply clamp the numbers. In games you also choose at which level to operate the PID loop thus making tradeof of code complexity and while still getting benefits of nicer looking animations. In real world you might want to control position of flying quadcopter while the thing you can directly control is speed of propellers with linear velocity, linear acceleration, angle, angular acceleration being between without a way to skip them.
My idea was to equip the control program with the equations of the system and some unknown parameters for friction and so on. Then estimate the parameters from the response to control inputs and drive the system through state space as hard as possible to get the fastest time, taking into account deviations from the expected state and reestimating parameters each time step. Would be really interested in knowing whether this could work or if this will just consistently slam into a wall. Response delay would probably make this a lot harder, but I did not look if any of the tasks simulates delays.
There's still a few reasons not to use it, though. Saving and restoring the float registers adds interrupt handling overhead. If you can fit into 16 bit integers, you can also use the 2 way SIMD instructions and get at least double the throughput.
Finally, floats themselves have a lot of footguns. You have to be very careful about propagating NaNs etc into control loops. It's also really easy (in C) to accidentally promote to double.
You don't need the fine precision or large range that floats have (we get those using exponents). Signal variations below a certain threshold are drowned out by the noise floor. Signals in control systems also have an expected maximum bound.
At other end, stability calculations based on quantization noise may be difficult with floats, since their least count changes with exponent. Fixed points have a uniform LC throughout its range.
Often these issues can be handled with very careful floating point order of operations (so long as -ffast-math isn't used...) but since its all implicit it's very easy to get wrong, while in fixed point you're forced to confront the scalings of different variables explicitly.
> full wine glasses that you absolutely must not spill balanced
I'm not sure what you mean by spilling. The liquids are usually contained in fully closed tanks and cannot spill. The thrust usually keeps the liquid at the bottom around the engine intakes. However, liquid sloshing inside the tanks is a problem. Even with slosh dampers, sloshing liquid manages to create attitude disturbances that can cause control instability unless managed carefully.
You do get baffles in liquid fuel tanks to cut down the effect, and some people have tried flexible bladders inside the rigid tanks for a similar reason but they don't work well with cryogenic fuels.
And then you'd gave to over engineer the rocket iself to not break when tipping over, not just the fuel tanks.