ev3dev-lang-python icon indicating copy to clipboard operation
ev3dev-lang-python copied to clipboard

Simulator for ev3dev or ev3dev-python

Open DJuego opened this issue 7 years ago • 48 comments

Hi!

I have ten hours of experience with ev3dev-python and I am pretty pleased. In fact I am considering seriously to use python-ev3dev in a educational environment.

The only weakness that I find is lacking of a simulator for learning/experimenting/working without robot.

Of course, to develop an accurate emulator is a HUMONGOUS project (!!!). However a toy simulator , similar to Open Roberta simulator would be a fantastic addition: A 2D top-down view of a two drive wheels mobile robot offers potential for learning and it is an inmediate visual feedback

Any related projects (robotic simulators in python): here, here and here

Any thought, suggestion, hint, idea or link in this direction? 👍

DJuego

P.S V-Rep seems promising. Would it be adapted?

DJuego avatar Nov 24 '16 22:11 DJuego

This is a very interesting concept. Firstly, I think that something like this would need to be implemented at the language binding/user program level, as both emulating the OS and drivers in situ would be a lot of work to do efficiently without a bunch of installation work. However, I think it would be relatively easy to modify the existing Python library so that file I/O could be replaced with proper calls to a simulated environment (preferably something that could be re-used by others as well). However, such an environment would need a "mock" implementation of the ev3dev motor and sensor drivers; this presents the challenge of keeping them in sync with changes to the real ones, because nuances can make a large difference. Optimally, you'd want a way to compile the existing drivers standalone for userspace so that you could both feed them your own input and intercept writes to PWM for motors. @dlech am I correct in assuming that there is no means of doing this that wouldn't cause difficulties in core driver maintenance? Do you have any ideas in this area?

In the end, I think that all the wrapper logic around the motor drivers would be easy, assuming any physics would be limited to 2D and an simple robot model. It's just a matter of getting the realistic logic working that translates ev3dev driver inputs to motor power outputs.

WasabiFan avatar Nov 25 '16 01:11 WasabiFan

@DJuego did you try the OpenRoberta system (https://lab.open-roberta.org). This has a built-inb simulator for the ev3/nxt. It is a bit higher level (we're using this in classrooms with kids staring 3rd grade).

ensonic avatar Nov 25 '16 08:11 ensonic

Thank you for your comments, @WasabiFan, Yes, yes. That is the idea. In the same vein of what i was thinking. Perhaps it is more easy to use the remote API of V-Rep. See this example.

@ensonic: Yes, yes. I know OpenRoberta System. :-) It is a powerful tool (intuitive, free, online but it is possible to work offline,...). In fact, I request to translate that simulator concept to ev3dev-python.

P.S:@ensonic, Do you use ev3dev with OpenRoberta? Does it work well? Or is it better to use the operating system for Open Roberta? What is your experience?

DJuego avatar Nov 25 '16 12:11 DJuego

@DJuego are you sometimes in IRC or the gitter chat? Don't want to hijack this bug report for discussion. Anyway, as quick pointers:

  • works offline: run the openroberta server on a raspberry pi 3 (I am doing this for events)
  • using ev3dev: you need a custom firmware for the ev3 anyway, if you use lejos, openroberta generates java, if you use ev3dev then openroberta generates python. I wrote the ev3dev connector for openroberta (https://github.com/OpenRoberta/robertalab-ev3dev) and I've been using it for quite a few events.

ensonic avatar Nov 25 '16 14:11 ensonic

@dlech am I correct in assuming that there is no means of doing this that wouldn't cause difficulties in core driver maintenance? Do you have any ideas in this area?

I would not recommend using Linux drivers as part of the simulation stack. It would limit you to running simulations on Linux only and add unnecessary complexity.

However, I think it would be relatively easy to modify the existing Python library so that file I/O could be replaced with proper calls to a simulated environment

I think this is the "right way" to go about doing something like this.

dlech avatar Nov 26 '16 17:11 dlech

The main issue that I see here is the ev3dev simulation logic itself: This type of virtual environment would need to have an implementation of the motor drivers available to translate driver input to duty cycle. Do you have any suggestions there? Or is it simple enough that an alternate implementation could be written and parity maintained without issue?

WasabiFan avatar Nov 26 '16 20:11 WasabiFan

This type of virtual environment would need to have an implementation of the motor drivers available to translate driver input to duty cycle

Not necessarily. If you are telling the motor to run at a fixed speed, then just have the simulation run the motors at that speed. If you are making a simple OpenRoberta-style simulator, there is no need to model the actual physics of the motor. For example, if speed_sp=400 and the simulation has a wheel diameter of 20 pixels, then the robot should be moving across the screen at 400 tacho counts per second / 360 tacho counts per rotation * (3.14 * 20) pixels per rotation = 69.8 pixels / second. Duty cycle does not come in to this equation at all.

If you want a simulator that is fancier than that, then you are beyond my expertise. :smiley:

dlech avatar Nov 26 '16 21:11 dlech

The problem is that you need to expose something resembling the interface of the real drivers. That means that commands, polarity, position, input constraints, PID dynamics (for positional control), ramping, state and stop actions would all need to be operational as they are in the real environment for consistent results. You could, of course, decide that it would only support the speed-control mode, immediate breaking, "running" state, etc., but at that point the simulation would probably not actually simulate real circumstances and would fail when you tried to use more than just the bare essentials of functionality.

I'll have to think over how this could work. There isn't an obvious answer that I can come up with but maybe I'll think of something.

WasabiFan avatar Nov 26 '16 21:11 WasabiFan

Of the simulators linked above do we know if any them support a plugin architecture where we could swap out them emulating say EVG-3 for a block of Python code?

dwalton76 avatar Dec 09 '16 04:12 dwalton76

I started playing around with making a very basic simulator. The init goal is just to have a single large motor appear as connected, will worry about simulating functionality later.

The problem is that we need to write to /sys/ which you cannot do from user space, even as root. What if we could trick the kernel into thinking a motor is connected...that would get us past the inability to write to /sys/.

@dlech when a motor is connected how does the kernel detect that it is connected?

dwalton76 avatar Jan 20 '17 21:01 dwalton76

You could write a dummy kernel driver to simulate the sysfs structure, but I think it would be much easier to just replace the functions that wrap calls to sysfs with something else. If this simulator is going to run on non-Linux systems, then that is also your only choice. FWIW, you can find the EV3 output port device connection manager here.

dlech avatar Jan 20 '17 21:01 dlech

In my mind, I think the ideal structure would be to intercept calls one level up: make an abstraction layer between the core library code and file I/O, then have an implementation of that layer which calls a separate Python module which operates the simulator. That avoids the file I/O and works cross-platform. Preferably the simulator code would expose an interface which is also usable by other languages.

WasabiFan avatar Jan 20 '17 22:01 WasabiFan

Can we mount an overlayfs to sysfs to shadow the real files? Or we have a fusefs replicating the relevant sysfs structure and the language bindings try two locations (first the fusefs one, then the sysfs one). We could even use some API to set the prefix and thus select between real and emulated.

ensonic avatar Jan 21 '17 10:01 ensonic

What I'd like to know is: Why would we want to emulate the files in any fs? If our goal is to make a simulator that runs on the desktop, isn't making it dependent on a Linux kernel counterproductive? I think we should be designing this thing to be entirely platform-independent, and cut out all the file I/O in the simulator.

WasabiFan avatar Jan 21 '17 16:01 WasabiFan

I was going to take the ev3dev bin and run it in a virtual box VM, I figure the closer we are to the real thing the better and virtual box will run on windows, linux and mac. My thought was the user launches the emulator then launches their robot code without making any changes to the robot code.

I think dlech makes a good point though that it might just be easier to have the python library look somewhere other than /sys/ if we want to run in emulator mode. So the user would

  • start the emulator which creates the needed filesystem structure somewhere other than /sys/
  • start the robot but pass it some flag on the command line to tell it to look at the emulated directory instead of /sys/

Perhaps then we wouldn't need virtual box.

dwalton76 avatar Jan 21 '17 18:01 dwalton76

@WasabiFan if the filesystem is emulated then we shouldn't need to change anything in ev3dev-lang-python other than telling it to look at the emulated directory instead of /sys/. That seems much easier than adding a code path to ev3dev-lang-python that allows it to function without file I/O. Maybe I am missing something though, what are your thoughts on how to do the simulator without file I/O?

dwalton76 avatar Jan 21 '17 18:01 dwalton76

@dwalton76 an alternative would be to do this in the platform probing and have a new emulated platform

ensonic avatar Jan 21 '17 19:01 ensonic

Am I missing something? Don't we just need to change

''' DEVICE_ROOT_PATH = '/sys/class' '''

In 'core.py'

rhempel avatar Jan 21 '17 21:01 rhempel

Am I missing something? Don't we just need to change

No, you're not missing something; if we want to have the library write to files and then the simulator read from them, that'll work. However, I am advocating for entirely bypassing the file I/O and intercepting calls between our external library interfaces and the I/O calls; that way we aren't using the hard drive for data transfer between modules, which seems nonsensical.

WasabiFan avatar Jan 22 '17 01:01 WasabiFan

I'll be honest I am not connecting the dots yet on what clear advantage we get by avoiding file I/O. Sure we could come up with something that avoids file I/O but why are we concerned about file I/O? My gut says we could pull off an emulator pretty quickly if we just point DEVICE_ROOT_PATH at a directory that is being manipulated by the emulator and in theory we shouldn't have to change anything else in ev3dev-lang-python. But if we want to do an emulator that avoids file I/O I don't see how we could do that without significant changes in ev3dev-lang-python.

dwalton76 avatar Jan 25 '17 14:01 dwalton76

I'll be honest I am not connecting the dots yet on what clear advantage we get by avoiding file I/O.

Disk I/O is not an interface to be used for live communication. Hard drives and their related software are designed for long-term storage, and as such they don't work well when you want to talk to other usermode software: it doesn't immediately invoke the other app, it puts needless pressure on system resources, and it wears down the physical media. Maybe this is a difference stemming from the fact that I've learned with Windows while you have with *Nix; it's important to keep in mind, however, that sysfs and memory-mapped files are not the same as real files on disk.

But if we want to do an emulator that avoids file I/O I don't see how we could do that without significant changes in ev3dev-lang-python.

The only I/O calls that motors and sensors invoke comes from the Device class. All we'd need is an alternative implementation of three methods. In reality, implementing this simulator while bypassing file I/O is likely easier than writing one that has to handle high-frequency reads and file watching.

WasabiFan avatar Jan 26 '17 02:01 WasabiFan

I think part of our misunderstanding here is assumption that file I/O implies disk I/O. which as you pointed out, is not always the case in linux given filesystems like tmpfs which are using ram and not a hard drive. So if we went the "emulate the filesystem" route we would certainly want to avoid writing to the SD card all the time and would use tmpfs or some equivalent. /var/run/ is one place we could do this, it uses tmpfs.

In terms of using the filesystem (not the disk) for communication, user space apps do this all the time with the kernel, the fact that we would have two user space apps communicating this way isn't a bad thing IMO. Heck even if we had the emulator communicate with the ev3dev-python code via a unix domain socket that is still just a file in the file system.

dwalton76 avatar Jan 26 '17 04:01 dwalton76

The only I/O calls that motors and sensors invoke comes from the Device class. All we'd need is an alternative implementation of three methods. In reality, implementing this simulator while bypassing file I/O is likely easier than writing one that has to handle high-frequency reads and file watching

But if we do this then the way you troubleshoot a robot changes a good bit if it is being emulated. I often do a cat of a file in /sys/class/tacho-motor/ to get the position of a motor or I echo a number into one of those files to write some value.

If the emulator and the app are not communicating via the filesystem in the same way the kernel and the app would communicate, then that is pretty fundamental change even if it is only three methods in the Device class that would need to be changed.

dwalton76 avatar Jan 26 '17 04:01 dwalton76

Something else that just came to mind, if we simulate the filesystem then it should be trivial for the other ev3dev programming language repos (Go, C, C++, etc) to also take advantage of the emulator.

dwalton76 avatar Jan 26 '17 04:01 dwalton76

I think I'm starting to see where our thinking diverged.

In my mind, an ev3dev simulator as described in this issue is software that allows you to run your ev3dev code on a development PC (whether that happens to be a desktop, laptop or dead badger, running any Python-supported OS) without the need for an EV3 or ev3dev installation available. There's no "SD card" in that scenario, and file I/O must inherently be assumed to be disk I/O (unless you fancy writing file system drivers for the aforementioned dead badger).

What have others been imagining?

WasabiFan avatar Jan 26 '17 05:01 WasabiFan

I guess I was picturing a virtual box image of ev3dev (plus the emulator), that way everything is as close as we can get it to the real thing. If they need to "apt-get install python-opencv" in the VM to make their robot work then they know they'll need to do the same thing on their ev3.

dwalton76 avatar Jan 26 '17 14:01 dwalton76

A virtual box is going to get as close as possible to running on real hardware. There are certain kinds of problems that will only show up that way. But there is also a lot of value in a less faithful simulation that runs natively on your development computer. Easier setup, using your IDE's debugger will be a breeze, etc. From my perspective, if real hardware is available then the primary advantage of a simulator is faster iteration, better debugging, and setup of test environments. I suspect all of these are going to be simpler and easier when running native.

With native simulation there are still two basic options:

  1. Manipulate stuff in the filesystem namespace so that ev3dev runs unmodified, except for perhaps a new root for where to look for files. This has a good architectural boundary and allows the simulator to be used with any language. I think the biggest risk is coming up with a portable and efficient mechanism to watch a hundred files for writes.

  2. Introduce an abstraction layer near the bottom of python ev3dev/core.py that allows the simulation to patch in its own attribute objects. They can still reside in a filesystem like namespace, but they are going to behave more like device drivers (albeit written in python). Super easy to make this portable (and pure python), but the boundary isn't quite as clean. I wrote a very simple proof-of-concept by monkey patching ev3dev. I think the approach is sound and would be cleaner if we introduced a real abstraction layer instead of patching. I think this also paves the way for fast unit tests of ev3dev and/or user code.

Dave-Baum avatar Feb 07 '17 04:02 Dave-Baum

I'd like to chime in on this thread from an education point of view.

What would be really useful to have is a python package that could be imported into a script on a PC and used to do a simple sanity check on a program before it is transferred to the device running ev3dev. This would enable the students to check for standard errors (indentation, missing colons, 'true' instead of 'True') without the overhead of transferring to the device.

It wouldn't have to be all that accurate, and wouldn't have to provide any sort of graphical/textual demonstration of what was going on. These would be nice, but I'd go with the maxim that the perfect can be the enemy of the good, and say that something that simply allowed program validation would be a huge benefit here.

Education environments tend to be locked down, so a simple module would be the best solution here.

loopspace avatar Apr 04 '17 13:04 loopspace

http://stackoverflow.com/questions/4284313/how-can-i-check-the-syntax-of-python-script-without-executing-it

dlech avatar Apr 04 '17 17:04 dlech

Compiling is a good way to catch indentation and syntax errors. I don't think it will catch true vs. True, or most other cases of typos in variable/function/method names.

Dave-Baum avatar Apr 04 '17 18:04 Dave-Baum