Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import from custom Python modules on new Lego Mindstorms Robot Inventor

I have been using the new LEGO® MINDSTORMS® Robot Inventor.

When creating a new "Project", the said project seems to contain a single file. However, at the start of every sample code file, one can see that the mindstorm modules are imported, like so:

from mindstorms import MSHub, Motor, MotorPair, ColorSensor, DistanceSensor, App
from mindstorms.control import wait_for_seconds, wait_until, Timer
from mindstorms.operator import greater_than, greater_than_or_equal_to, less_than, less_than_or_equal_to, equal_to, not_equal_to
import math

Does anybody know how can I create my own modules, and import them into a given project? Is it possible?

like image 217
Pedro Pinheiro Avatar asked Jan 25 '23 16:01

Pedro Pinheiro


1 Answers

Update 2022-02-21

After getting back into this, the original solution no longer works. Lego changed the directory structure for projects. Each upload creates:

  • a random number directory with projects
  • a __init__.mpy file which is the compiled version of your sent code

The above means that we can no longer read from the uploaded code to run. What we can do instead is create files elsewhere on the file system to get our code to persist.

For example, this MVP will achieve what you need:

  1. Upload the following:
    content = """
    __version__ = "0.1.1-20220221"
    
    def hello() -> None:
        print("hello from {}".format(__version__))
    """
    
    f = open("mindstorms/custom.py", "w")
    f.write(content)
    f.close()
    
  2. Create a second project with the following:
    from mindstorms.custom import hello
    
    hello()
    

The previous solution was brittle, and I'm unsure when the change that broke it actually occurred. I've tested this on Hub OS 3.1.43 and it works. I do not like this solution, since you're just writing out the file and it makes it a little worse for editing, but at least this is fine.

Why mindstorms.custom? That seems like a fine place to put your own custom functionality, it is unlikely to be overwritten by the official Mindstorms distribution, and centralizes all of the code in one place. You could create your own directory off of root and put the file(s) there, but for the sake of ease-of-use, let's just do this.

As before, keeping the older answers below.


EDIT: spent some more time on this, and figured it out! I'm keeping the original answer below. Here's a short reproducible solution. Tested working with (taken from os.uname)

sysname='LEGO Technic Large Hub'
nodename='LEGO Learning System Hub'
release='1.11.0'
version='v1.11-1139-gf7407e5a0 on 2020-06-19'
machine='LEGO Technic Large Hub with STM32F413xx'
  1. Create a new python project with this content:

    import os
    import sys
    
    def example() -> None:
        print("imported")
    
    # EOF
    
    # upload the module to the Hub
    print("beginning upload from {}...".format(__name__))
    os.chdir("projects")
    open("__init__.py", "w").close()
    filename = "{}.py".format(__name__.split("/")[-1])
    new_filename = "mystorms.py"
    try:
        os.remove(new_filename)
    except:
        print("{} does not exists".format(new_filename))
    os.rename(filename, new_filename)
    # remove everything after EOF
    with open(new_filename, "r") as f:
        content = f.read()
    content = content.split("# EOF")[0]
    with open(new_filename, "w") as f:
        f.write(content)
    print(os.listdir())
    
    sys.exit()
    

    The stuff after # EOF does the actual "uploading" and ensures that when you try to import this elsewhere, you don't re-"upload" it. Note that, in regular python, you'd wrap this in if __name__ == "__main__", but Mindstorms doesn't use that convention when it's running.

  2. Send that project to your Hub and run it. Note that you'll have those files that persist on your Hub, and I have no idea if there are memory constraints that you'll need to worry about.

  3. Create a new python project with the following:

    import os
    
    import projects.mystorms as ms
    
    print(os.uname())
    ms.example()
    

The above should work. Note that if you need to update the file, you'll have to adjust the module code to delete the original if it exists, but that's a minor change. I have not done anything beyond the above, but this could lead to a way to get missing stdlib stuff into Mindstorms as well.


Haven't found a solution, but I did go through most of the standard library to see what else you can import which is kind of related... The below did not throw an error, but I have not yet attempted anything with the packages themselves.

import array
import builtins
import cmath
import ctypes
import errno
import gc
import hashlib
import heapq
import io
import json
import math
import os
import random
import re
import select
import struct
import sys
import time

The underlying theme seems to be limiting access to the filesystem and forcing any async operations to be done with the actual Mindstorms methods (e.g. hub.speaker.start_beep() and the like). There is some directory structure (the 0-19 files), but I haven't figured out if that can be used to achieve what you need.

Also interesting to note is that you can't import typing, but you can use type hints in your functions. I also strongly dislike that you can't copy-paste from the console.

like image 193
mmoran0032 Avatar answered Jan 29 '23 21:01

mmoran0032