Yes, Lua tables are incredibly versatile tool. I'm not a fan of global-scope-by-default and of verbosity, but other than that it's a fantastic language.
Global scope by default isn't good practice in embedded. Global scope isn't synonymous with static allocation, but unfortunately that goes over the head of many people. Best practice in embedded is to have locally scoped statically allocated data passed around by reference.
It really depends on the application. For smaller, more targetted embedded applications, global scope is fine. If every function needs to have access to a common set of variables, there's really no need to be passing references around.
Even if the application is tiny, that's no excuse. It makes it even easier to chuck everything into a single struct type. It's not like there's any performance gain to having globally scoped stuff on a modern compiler compared to passing references.
One reason using global variables is bad practice is it makes testing harder. An unfortunately high percentage of embedded software doesn't have any sort of harness-based testing because it's written with globals spammed everywhere, which prevents you from using any kind of principled testing strategy where you mock out all the hardware dependencies. It's especially bad if there's globally defined MMIO stuff like "#DEFINE CCR1A (uint64_t)0x74FEA10". Good luck testing that!
Smaller embedded targets don't have modern C++ compilers. Also many engineers want to solve domain problems instead of dealing with C++ related problems.
In domain of C, passing by reference means passing pointer. If you chuck everything into single struct and pass by pointer, it has same problems as global scope.
Not that I'm advocating for global variables. Even tiny projects tend to grow with time, and localizing scope across the code base is not fun at all. In context of Lua, I've just trained myself to prefix variables with 'local' and I don't give it much thought.