(Pseudo) multi-tasking?

Loop() goes round and round.

For every action, everything watched, you set up within loop() an if to check if it is time or other condition to run that bit of code which should be kept short so the rest is not delayed.

Example: one action is to receive serial data. Get the characters 1 at a time and if possible, evaluate them as they come in. Even at 115200 baud there is a lot of microseconds between characters to do other tasks. If you buffer and wait for end of transmission then you are creating a longer task later.

What order you arrange your tasks can make a difference. Use Occam's Razor.

At the end of a task, consider writing in a return. That will start loop() over again immediately.

Each task, write as asynchronous code. As above, keep the steps short (make steps, not "now I will parse and lex the string, doh-de-doh!"), accomplish a little bit on the cycle and fast loop() cycling will become smooth tasking. You'll know when it's 'full'. Also if you can, avoid using floats or at least trim down on floating point operations where possible, Arduino has no FPU.