I used gpiozero and RPi.GPIO to control my 3D printer. However, the speed was quite slow. After some nerve-wracking debugging, I found that Python was causing the slow motion of the motors. Even after deleting the time.sleep() line, it still ran slowly. This left me with no choice but to rewrite my control module in C. After the rewrite, the problem was finally solved.
In the C code, I chose the wiringPi library to control the GPIO pins.
The GPIO numbering systems used by gpiozero, RPi.GPIO, and wiringPi are quite different. Use this command to get the pin-number map for your Raspberry Pi:
gpio readall
Then wrap the C code as a Python extension module.
Create a file named test.c and define the Python module functions there. The important part is that the exported initialization function must match the module name used in setup.py.
Create a file named setup.py to build the extension. Since the extension links against wiringPi, specify it in the extension configuration:
from distutils.core import setup, Extension
module = Extension(
'keywdarg',
sources=['test.c'],
library_dirs=[''],
libraries=['wiringPi'],
)
setup(
name='keywdarg',
version='1.0',
description='Python C extension using wiringPi',
ext_modules=[module],
)
Once the code is finished, build and install it. I suggest installing it inside a virtual environment.
sudo apt install python-virtualenv
python setup.py build
python setup.py install
You might meet some problems while compiling or importing the module.
Table of Contents
Python.h: No such file or directory
This is a compiling error. Reinstalling python3-dev solved it for me.
sudo apt install python3-dev
undefined symbol: digitalWrite
Because the extension uses the wiringPi library, it must be specified in setup.py. Otherwise, Python may import the compiled module but fail when it tries to resolve digitalWrite().
Extension(
...,
library_dirs=[''],
libraries=['wiringPi'],
)
ImportError: dynamic module does not define init function
I had named the initialization function incorrectly. For Python 3, PyInit_keywdarg must have the same suffix as the module name defined in keywdargmodule.
static struct PyModuleDef keywdargmodule = {
PyModuleDef_HEAD_INIT,
"keywdarg",
NULL,
-1,
keywdarg_methods
};
PyMODINIT_FUNC
PyInit_keywdarg(void)
{
return PyModule_Create(&keywdargmodule);
}
SystemError: Bad call flags in PyCFunction_Call. METH_OLDARGS is no longer supported!
In the PyMethodDef array, the method flags should be defined as:
METH_VARARGS | METH_KEYWORDS
For example:
static PyMethodDef keywdarg_methods[] = {
/* The cast of the function is necessary since PyCFunction values
* only take two PyObject* parameters, and keywdarg_parrot() takes
* three.
*/
{"parrot", (PyCFunction)keywdarg_parrot, METH_VARARGS | METH_KEYWORDS,
"Print a lovely skit to standard output."},
{NULL, NULL, 0, NULL} /* sentinel */
};
More detail is available in the Python documentation:
