Why can't VSCode load MicroPython 'machine'? - python

I have installed the MicroPython IDE and Python extension in accordance with the VSCode instructions. This is my first use of VSCode and I have searched for a solution and failed. when I try to debug this code:
import machine
import time
led = machine.Pin(2, machine.Pin.OUT)
button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP)
while button.value():
led.on()
time.sleep(1)
led.off()
time.sleep(1)
led.on()
I get this result: Module Not Found Error "no module named 'machine' "
I would very much appreciate your assistance.
Regards
John

You are dealing with two separate Python environments:
The "PC Python" (also called CPython) on your development machine
MicroPython running on embedded device like ESP32.
When testing on PC, you are running your code in CPython. But if you transfer it to the device, it runs within MicroPython. Both environments are very similar but some differences exist.
The machine module is one such difference. It exists only in MicroPython and allows actual access to the hardware. Thus, if you run your program in CPython, you get exactly the error you described.
You can either test your program on an actual device. Or you "mock" the machine module, i.e. you create that module as "dummy" implementation for testing on PC. It would at least need to contain the Pin() class, which could for example print the state changes to command line.
There is an example for such a mock on GitHub: https://github.com/tflander/esp32-machine-emulator
A minimal example for your case: Create machine.py containing:
class Pin:
IN = 0
OUT = 0
PULL_UP = 0
def __init__(self, number, mode=-1, pull=-1):
self.number = number
def on(self):
print('Pin %d switches ON' % self.number)
def off(self):
print('Pin %d switches OFF' % self.number)
def value(self):
return 1
# ... add other methods when needed ...
... and put it somewhere where your script can import it from.

Related

Python libgpiod vs gpiod packages in Linux?

I wrote a little test program in Python to manipulate GPIO pins on an an Intel Up Xtreme i11. First running under NixOS, I brought in the package as "libgpiod" and things are working. (MacOS package managers also know "libgpiod".) Then I tried to port this to an Ubuntu world on the same hardware. But apt and apt-get know nothing of libgpiod, they only know gpiod. pip3, too. So I installed gpiod, but the discrepancies mount up…
gpiod has a member "chip" rather than "Chip"
chip.get_line gets Error 22 for any small integer I can find.
What I lack is documentation. Is there something, somewhere, that clearly explains the distinction between these two packages that appear to be similar but are not? And what is actually the correct way of using the Ubuntu gpiod package in Python?
BTW I am running as root in both cases. Here's the code (gpiod version):
import gpiod, time
# pins
POWER = 9
chip=gpiod.chip('gpiochip0')
power=chip.get_line(POWER)
power.request(consumer="motor_movement", type=gpiod.LINE_REQ_DIR_OUT)
def run():
delay = 1.0
try:
#power.set_value(0)
while True:
power.set_value(1)
time.sleep(delay)
power.set_value(0)
time.sleep(delay)
finally:
cleanup()
def cleanup():
power.release()
if __name__ == "__main__":
run()
What you refer to as "libgpiod" library are system packages based on this C library.
From its documentation:
libgpiod
========
libgpiod - C library and tools for interacting with the linux GPIO
character device (gpiod stands for GPIO device)
Since linux 4.8 the GPIO sysfs interface is deprecated. User space should use
the character device instead. This library encapsulates the ioctl calls and
data structures behind a straightforward API.
The library also provides python3 bindings, which have probably been using.
On Ubuntu you would install everything you need issuing:
apt install python3-libgpiod.
Your code using this library should have looked like this:
import gpiod, time
# pins
POWER = 9
chip = gpiod.Chip('0')
power = chip.get_line(POWER)
power.request(consumer="motor_movement", type=gpiod.LINE_REQ_DIR_OUT)
def run():
delay = 1.0
try:
#power.set_value(0)
while True:
power.set_value(1)
time.sleep(delay)
power.set_value(0)
time.sleep(delay)
finally:
cleanup()
def cleanup():
power.release()
if __name__ == "__main__":
run()
For further usage examples see the examples section on the repo.
The python package gpiod available through pip from pypi.org is, "a pure Python library and has no dependencies on other packages". So no relation to the C library mentioned above.
See also this question for differences or advantages using one or the other.
There is a basic example provided as documentation.
To make your code working using python3-gpiod (the library installed through pip), you should modify as follows:
import gpiod, time
# pins
POWER = 9
chip=gpiod.chip('gpiochip0')
power=chip.get_line(POWER)
power_config = gpiod.line_request()
power_config.consumer = "motor_movement"
power_config.request_type = gpiod.line_request.DIRECTION_OUTPUT
power.request(power_config)
def run():
delay = 1.0
try:
#power.set_value(0)
while True:
power.set_value(1)
time.sleep(delay)
power.set_value(0)
time.sleep(delay)
finally:
cleanup()
def cleanup():
power.release()
if __name__ == "__main__":
run()
Alternatively try to use help(gpiod.line.get_line) or similar to troubleshoot your code.

How do I start a COM server? Code is in Python

I want to run Python code as a COM server. Eventually I want to run an RTD server available here. But first I want to know what exactly you have to do to getting any COM server running. So let's focus on this example.
class HelloWorld:
_reg_clsid_ = "{7CC9F362-486D-11D1-BB48-0000E838A65F}"
_reg_desc_ = "Python Test COM Server"
_reg_progid_ = "Python.TestServer"
_public_methods_ = ['Hello']
_public_attrs_ = ['softspace', 'noCalls']
_readonly_attrs_ = ['noCalls']
def __init__(self):
self.softspace = 1
self.noCalls = 0
def Hello(self, who):
self.noCalls = self.noCalls + 1
# insert "softspace" number of spaces
return "Hello" + " " * self.softspace + who
if __name__=='__main__':
import win32com.server.register
win32com.server.register.UseCommandLine(HelloWorld)
Ok, this works in the way that there were no errors and server is registered, hence it is available in the HKEY_CLASSES_ROOT registry. But what can I do with this? Some say you have to compile a instance and have a .dll or .exe file. WHat else do I have to do?
Well, I ran your example. The registry key for the server is at:
HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{7CC9F362-486D-11D1-BB48-0000E838A65F}
It has two subkeys... one for LocalServer32 and one for InProcServer32
I created a simple VBA macro in Excel:
Sub d()
Set obj = CreateObject("Python.TestServer")
MsgBox obj.Hello("joe")
End Sub
Macro ran just fine. My version of Excel is 64-bit. I ran the macro and then fired up Task Manager while the message box was being displayed. I could see pythonw.exe running in the background.
The only difference between my python script and yours is probably the name and also that I added a line to print to make sure I was executing the function:
if __name__=='__main__':
import win32com.server.register
print("Going to register...")
win32com.server.register.UseCommandLine(HelloWorld)
When I ran the 64-bit csript.exe test, it worked... as expected... when I ran the 32-bit version it failed.
I know why...sort of...
The registry entry for InProcServer32 is pythoncom36.dll
That's no good. It is an incomplete path. I tried modifying the path variable on my shell to add to one of the 3 places where the DLL existed on my system, but it didn't work. Also, tried coding the path in the InProcServer32. That didn't work.. kept saying it couldn't find the file.
I ran procmon, and then I observerved that it couldn't load vcruntime140.dll. Found the directory under python where those files were, and added to my path. It got further along. If I cared enough, I might try more. Eventually using procmon, I could find all the problems. But you can do that.
My simple solution was to rename the key InProcServer32 for the CLSID to be _InProcServer32. How does that work? Well, the system can't find InProcServer32 so it always uses LocalServer32--for 32-bit and 64-bit processes. If you need the speed of in process then you'd need to fix the problem by using procmon and being relentless until you solved all the File Not Found errors and such. But, if you don't need the speed of in process, then just using the LocalServer32 might solve the problem.
Caveats I'm using an Anaconda distro that my employer limits access to and I can only install it from the employee store. YMMV.

How do you get a module to function, and be recognized from within Choreographe on a Nao robot?

I'm using a Nao robot, and the python SDK, and I'm trying to create my own module for it. Right now it is just a dummy module with one function: getJoke().
I have my file tellAJoke.py located under the path /home/nao/tellAJoke.py and I have updated the autoload.ini file to include the following:
[python]
/home/nao/tellAJoke.py
When I boot up the robot, it says what it normally does on startup, but also says what my getJoke() function returns, "This is a bad joke".
I'm not sure what I'm doing wrong here. When I ssh onto the robot, and run the code it runs just fine, but never when I want to import the module with ALProxy in Choreographe.
EDIT: I added the actual dummy code I have.
from naoqi import ALBroker
from naoqi import ALModule
from naoqi import ALProxy
import sys
class JokerModule(ALModule):
"""Tells you a random joke"""
def __init__(self, name):
print "WE HAVE INITED"
self.tts = ALProxy("ALTextToSpeech")
ALModule.__init__(self, name)
global memory
memory = ALProxy("ALMemory")
memory.subscribeToEvent("SayingJoke", "Joker", "getJoke")
def getJoke(self, *_args):
"""Returns a joke"""
self.tts.say("Joke time!")
def main():
"""main entry point"""
pip = '192.168.1.104'
pport = 9559
myBroker = ALBroker("myBroker", '0.0.0.0', 0, pip, pport)
global Joker
Joker = JokerModule("Joker")
speechProxy = ALProxy("ALTextToSpeech")
Joker.getJoke()
if __name__ == '__main__':
main()
Here is a guide on making services (a.k.a. "modules", but that term is confusing because it has another meaning in Python): http://doc.aldebaran.com/2-4/dev/libqi/guide/py-service.html (this doc is for NAOqi 2.4 but things should work mostly the same for 2.1, which is more often used on NAO)
But, you might want to try Robot Jumpstarter, that contains templates for various typical projects, including a python service (that works as explained in the document above).
clone it and run python jumpstart.py python-service tell-a-joke TellAJoke
... and it will generate a project that you can:
install on the robot witch Choregraphe
run in standalone with python tell-a-joke/app/scripts/tellajoke.py --qi-url your-naos-ip
... and in both cases you will be able to call it from from Choregraphe boxes etc.
(edit)
Now that you posted your code - in this specific case your problem is just that after Joker.getJoke(), your program reaches the end and terminates. The usual "modern" way of doing that would be with a qi.Application() that would .run() (all that is done in the jumpstarter template). You could do a while True: sleep(1) or something, which is not very pretty but would work (I recommend migrating to NAOqi 2, and instead of using ALProxy and ALBroker, use session.service and qi.Application ... the two are interoperable)

pyusb: cannot set configuration

I am trying to make a script (on linux) that can turn a light in my mouse on or off.
This is the code I have so far:
import usb.core
import usb.util
import sys
interface = 0
dev = usb.core.find(idVendor=0x1532, idProduct=0x0017)
def main():
if dev is None:
print "device not found"
else:
print "device found"
if dev.is_kernel_driver_active(interface) is True:
print "but we need to detach kernel driver"
dev.detach_kernel_driver(interface)
print "claiming device"
usb.util.claim_interface(dev, interface)
print "release claimed interface"
usb.util.release_interface(dev, interface)
print "now attaching the kernel driver again"
dev.attach_kernel_driver(interface)
print "all done"
return 0
if __name__ == '__main__':
main()
This works fine but if I try to do a: dev.set_configuration()
after the claim_interface(dev, interface)
the script returns the error: usb.core.USBError: Resource busy
Why is it still busy after I have detached its kernel driver?
Not sure if this will solve, but are the udev rules for your mouse being set up correctly? I had a similar problem with a custom device a friend did for me and I solved by adding a rule like:
SUBSYSTEM !="usb_device", ACTION !="add", GOTO="device_rules_end"
SYSFS{idVendor} =="1532", SYSFS{idProduct} =="0017", SYMLINK+="mydevice"
MODE="0666", OWNER="<your-username-here>", GROUP="root"
LABEL="device_rules_end"
in my /etc/udev/rules.d folder.
HTH!
EDIT: Before adding the rule, try running your script with sudo. If it will work that way it's almost certainly a permission setting that will be fixed by the above rule.
I had this problem too. Your code works well if you "set_configuration" first and only then claim the interface. This is also the order suggested here: http://libusb.sourceforge.net/api-1.0/caveats.html

Why does calling kernel32.GetModuleHandleA() for msvcr100 fail in Python?

I am having a problem with calling GetModuleHandleA() using Python. I have a module that attaches as debugger to the process. I'm working on a function that would return address of the function in the specific DLL module. GetModuleHandleA("msvcr100") fails all of the time.
from ctypes import *
kernel32 = windll.kernel32
Function declared as part of a bigger debug class. That's the part of function declaration:
def resolve_function(self,dll,function):
handle = kernel32.GetModuleHandleA(dll)
if handle == False:
print "kernel32.GetModuleNameA() failed!!!"
return False
address = kernel32.GetProcAddress(handle, function)
if address == False:
print "kernel32.GetProcAddress() failed!!!"
return False
kernel32.CloseHandle(handle)
return address
Call the function made as:
function_address = debug.resolve_function("msvcr100", "printf")
I run separate process that uses printf() and then attach to it. Everything works fine until I get to GetModuleHandleA() that returns False all of the time.
Code that runs printf():
from ctypes import *
import time
msvcr100 = cdll.msvcr100
counter = 0
while 1:
msvcr100.printf("Counter = %d\n" % counter)
time.sleep(1)
counter += 1
Any ideas?
You've found the solution to your problem, but I'm answering anyway to explain why your original effort failed (and why your fix worked).
First, msvcrt/msvcr100 are two different versions of Microsoft's C runtime library. There are other versions as well, and all of them contain their own definitions for printf(). A given process may have any one of them loaded, or multiple versions loaded, or no versions loaded - it's possible to produce console output using only WinAPI functions! In short, if it's not your process, you can't depend on any given version of the C runtime being available.
Second, GetModuleHandle() doesn't load anything. It returns a handle to the named module only if it has already been loaded. msvcr100.dll can be sitting right there on disk, but if the process hasn't already loaded it then GetModuleHandle won't give a handle to you. LoadLibrary() is the function you'd call if you wanted to both load and retrieve a handle to a named module... But you probably don't want to do this in a process you don't own.
FWIW, Process Explorer is a handy tool for viewing the DLLs already loaded by a process.
After modifying:
...
handle = kernel32.GetModuleHandleA(dll)
if handle == False:
error = GetLastError()
print "ERROR: %d - %s" % (error, FormatError(error))
return False
...
I get: ERROR: 126 - The specified module could not be found
I actually replaced msvcr100.dll with msvcrt.dll in my code and it worked perfect. I found out that msvcrt.dll is system dll. msvcr100.dll ships with Studio 2010. They are both located in C:\Windows\system32. It is still a mystery for me why msvcr100.dll did not work.
Use GetLastError() (or WinError) from ctypes to find out why you're getting a NULL return, then add that information to your error message. Even after you figure out this specific problem, you'll want that more robust error reporting.
See the ctypes docs for details: http://docs.python.org/library/ctypes.html
Try calling:
msvcr100 = cdll.msvcr100
before calling:
function_address = debug.resolve_function("msvcr100", "printf")
to make sure the DLL is loaded in your process. msvcrt might work because it was already loaded.

Categories

Resources