From 69aab5bbf181d6ba4751e1ec25dc32212242a091 Mon Sep 17 00:00:00 2001 From: Sebastian Romero Date: Tue, 10 May 2022 08:33:30 +0200 Subject: [PATCH 1/3] Add tutorial data --- .../assets/py-serialrpc.zip | Bin 0 -> 2190 bytes .../assets/python-sensor-rpc.zip | Bin 0 -> 8548 bytes .../python-arduino-data-exchange/content.md | 119 ++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/assets/py-serialrpc.zip create mode 100644 content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/assets/python-sensor-rpc.zip create mode 100644 content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md diff --git a/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/assets/py-serialrpc.zip b/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/assets/py-serialrpc.zip new file mode 100644 index 0000000000000000000000000000000000000000..11eb4550c1e732d5d40cf2437c215273a0c04142 GIT binary patch literal 2190 zcmWIWW@h1H00Hl*6(L{-l;CBMVJN87Elw@UOw1`NNY)Px;bdU0TWgcl0K}yg+zgB? zUl|z~SVVvt0^r72q8THOZVZ}%u|UJ(2pPDZdsBfh&>9d{$8BIyYGG++QEF~#UP-ZD zNks|R#UKmfF)hd~PA^DI&ejF`Ot+x2BqKkM3*-rqXE+!@o>;TvlF|+!?cJjglM`2Hw=_7rdHX*J%S7VZsK4?j+7RW8i4@2<*^o9VW264yFS_H#Yu@p*e5 z&G}+bsHfL5lktbdpWB}=C7Xx7UDej-!Z5GxET8E-wQCl~?ySmw-nNeU|GmW<6rSJG zP~BoCF0CQ6*mlFBtM%97-7=sytSiCd7N@T8+xP>C&1TmuFYFoUn>26`O?#Wo4l>t3up6dzu4V% zbDR$8c8JyTU;M@_2Chl?}BI$VWgW`8!~KKJqYvN=D*w04IVEb%lD z?DgIAi9<(fajo+icV6E;4;aqz+^u|e!K`Ub?Yj2bO}lk=sF>{%;y!+_?SJ3q!g+iJ z-xTvEeZGE7AiJmQ*gq!Jlzn^J^sk1%RBZ&r^7x}sFFg~Hi_$Tp()+xQ=SiJSK^HDx zW?%T_jL_dZf2LfTb0z6-)2T^4e{Ak9YD&3#rR&I@ra2*hA1zAJ0~ZvCxR32Ce>@rJ zici>Fk^;_Iy2<&u1^LCPdX>33_~JaY?;>B50gvnbzg=zR&kTen{o`4A;l-q0-Mazb zz8?x`*7tq)@?@^^>B~GaA6W#7WFvVZIS)@`%-g(CxykB(#ld42=YBk|A7i05sm0-& ztEJeqAU6-A&&L;R{65)sQ>CusijvTv50f6%?QL6ib=T3{H{NlR0{(yaxL`-N>=Av* z+3yz3^2@yX=F@|@i!*EgXCH`K;-4Sj&B!FjjH`5&0QwmO1Q^~rf@rj|mK9RgVq_hJ zk(ebdvXSoSM#3`>upkE-4k{K27>-)%LJS9HQidgsGjJP@Sq9^?43QL2i(6#Ncz|}I z1P;O{$b~OHYp}VBUf0W?20PZVr;fBvQ2+L4&GO}gQ rnDP1slCO!g1T~W)TT;M+W(l?|i^~#LHeezG*0mfAGC;S+u!491zPYmn literal 0 HcmV?d00001 diff --git a/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/assets/python-sensor-rpc.zip b/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/assets/python-sensor-rpc.zip new file mode 100644 index 0000000000000000000000000000000000000000..d5133663d727cb92ae66fde1c23d8310276f5849 GIT binary patch literal 8548 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 E42C module) + +## Python on the X8 + +Python is a modern and powerful scripting language that can be used for all sorts of use cases. In this tutorial we only read sensor data from an Arduino sketch without doing anything interesting with it, but you could extend the example and process the data further. + +### Communication Between Linux and Arduino Sketches + +The python script will run on the Linux side and therefore on the iMX8 processor. The Arduino sketch on the other hand will run on the STM32H747 microcontroller. That allows for real-time processing on the Arduino side while running a fully fledged operating system on iMX8. However the two processors need a communication mechanism to exchange data with one another. The communication mechanism that is being used is referred to as RPC (Remote Procedure Call). To facilitate the communication the M7 core on the STM32H747 microcontroller is used which hands over any data / request to the M4 core. That means your Arduino sketch will solely run on the M4 core. Dual core processing on the Arduino side is currently not supported. + +On the Linux side there is a service that takes care of sending data between the two worlds. It's called `m4-proxy`. You can check if the service is running by logging into the X8 via `adb shell` and then executing `sudo journalctl -fu m4-proxy`. If, for whatever reason, the service has stopped, you can restart it with `sudo systemctl restart m4-proxy` + +## The Arduino Sketch + +The Arduino sketch to read sensor data doesn't look much different from an ordinary sketch. The only thing that differs is that we expose the sensor data via RPC. + +```arduino +RPC.bind("temperature", []{ return bme.temperature; }); +RPC.bind("humidity", []{ return bme.humidity; }); +RPC.bind("pressure", []{ return bme.pressure / 100.0F; }); +RPC.bind("gas", []{ return bme.gas_resistance / 1000.0; }); +RPC.bind("altitude", []{ return bme.readAltitude(SEALEVELPRESSURE_HPA); }); +``` + +Two additional header files need to be included: + +```arduino +#include +#include +``` + +The bind function makes the data available via the specified name e.g. "temperature". In our example an anonymous function is created that returns the corresponding sensor property whenever requested. Alternatively you could bind the name to an existing, named function instead. The data can then easily be requested using that name (e.g. "humidity") by querying the `m4-proxy` service. Once data is being requested it is packaged as a message and sent over SPI to the iMX8. + +You can find the sketch in the software package [here](assets/python-sensor-rpc.zip). You may need to change the sketch depending on what sensor you would like to read from. If you're using an I2C sensor, you can connect SCL to **PWM6** and SDA to **PWM8** on the Portenta breakout. That's because the labeled I2C pins on the Portenta Breakout are only available on the Linux side. If you're using an analog sensor you can connect it to any analog pin. Please refer to the pinout diagram on the Portenta Breakout [documentation page](/hardware/portenta-breakout). + +Make sure you've installed the "Arduino Mbed OS Portenta Boards" core and upload the sketch to the X8 in the Arduino IDE or via Arduino CLI. + +### Debugging the Arduino Sketch + +To check if the Arduino sketch is working correctly you may want to read the messages from the `Serial.println` statements. You can't currently read them directly in the serial monitor of the Arduino IDE. Instead, you can use a simple service called `py-serialrpc` which listens for those messages and prints them to the console. This service needs to run on the Linux side of the X8. You can get the files [here](assets/py-serialrpc.zip). Upload them to the X8 with `adb push py-serialrpc /home/fio`. + +Log into the X8 shell with `adb shell` and navigate into the `serialrpc` folder. Build the container using `sudo docker build . -t py-serialrpc`. The `-t` flag assigns a tag to the container. Then run the container by executing `cd..` and then `sudo docker-compose up -d`. The `-d` flag detaches the container so it runs in the background. Note that this will run the docker container persistently across reboots by registering it as a systemd service. To stop the container, run `sudo docker-compose stop`. + +Check if the container is running by executing `sudo docker ps`. You can then access the log of this service at any time by executing `sudo docker-compose logs -f --tail 20` from the **same directory**. If you don't run the container in the background (skip the `-d` flag), you will get the console output directly in the executing shell. Once the container is running you will see the messages that are being sent from the M4. + +## The Python Application + +The Python application requests the sensor data from the M4 over RPC and unpacks the message. Data can be requested by calling the function exposed over RPC on the M4 e.g.: + +```python +m4_proxy_address = 'm4-proxy' +m4_proxy_port = 5001 +rpc_address = RpcAddress(m4_proxy_address, m4_proxy_port) +rpc_client = RpcClient(rpc_address) +temperature = rpc_client.call('temperature') +``` + +The files for the complete Python application can be found in the same package as the Arduino sketch (see above). Upload the `python-sensor-rpc` folder to the X8 via `adb push python-sensor-rpc /home/fio`. Log into the X8 via `adb shell`. Then navigate into the `python-sensor-rpc` folder and execute `sudo docker build . -t python-sensor-rpc`. When it's done you can run the container with `sudo docker-compose up`. After a few seconds you should see the output from the Python application featuring the sensor readings on the M4 that were piped through the RPC mechanism. The output should look similar to the following: + +``` +python-sensor-rpc_1 | ============================================ +python-sensor-rpc_1 | == Portenta X8 Sensor reading == +python-sensor-rpc_1 | ============================================ +python-sensor-rpc_1 | +python-sensor-rpc_1 | Temperature: 25.904266357421875 +python-sensor-rpc_1 | Humidity: 25.564695358276367 +python-sensor-rpc_1 | Pressure: 976.4400024414062 +python-sensor-rpc_1 | Gas: 136.496 +python-sensor-rpc_1 | Altitude: 311.0769348144531 +``` + + Keep in mind that, whenever you change anything in the Python script on your computer you will have to sync it back to the X8 and re-build the container: + +``` +# On your computer +adb push python-sensor-rpc /home/fio + +# On X8 +sudo docker-compose down +sudo docker build . -t python-sensor-rpc +sudo docker-compose up +``` + +Alternatively you could modify the files directly on the X8 using an editor such as VIM so you don't need to upload the files all the time. Re-building the container will be necessary in any case though. In case you wonder how to specify the python script that is executed when running a container, have a look at the `Dockerfile` file. There you'll find the `ENTRYPOINT` command that takes multiple arguments. In our example: `ENTRYPOINT [ "python3", "m4_to_python.py"]` + +## Conclusion + +In this tutorial you learned how to use the docker infrastructure to build a container that runs a python application. You have also learned how to use the RPC mechanism to exchange data between the microcontroller and the iMX8 which runs the Linux operating system. + +### Next Steps + +- You may now further process the data that you receive from the Arduino sketch and e.g. upload it to a cloud service or similar. +- Familiarize yourself with Docker commands to adjust the docker configuration to your needs. \ No newline at end of file From e3e1c8f6aa4546b527793d0fc078dd81f19af234 Mon Sep 17 00:00:00 2001 From: marqdevx Date: Tue, 10 May 2022 13:05:06 +0200 Subject: [PATCH 2/3] Fix requirements header --- .../tutorials/python-arduino-data-exchange/content.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md b/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md index 2b632f9303..477d6cd652 100644 --- a/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md +++ b/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md @@ -20,7 +20,7 @@ The container infrastructure provided by Arduino contains a pre-built Python ima - Learn how to modify a container and run it - Learn how to use commands to debug the container and service infrastructure -### Required Hardware and Software +## Required Hardware and Software - [Portenta X8](https://store.arduino.cc/products/portenta-x8) board - [Portenta breakout](https://docs.arduino.cc/hardware/portenta-breakout) board From 76e2fed2250c9b6810cff808e9e32ee118726939 Mon Sep 17 00:00:00 2001 From: marqdevx Date: Tue, 10 May 2022 13:34:49 +0200 Subject: [PATCH 3/3] make wording I2C with sup --- .../tutorials/python-arduino-data-exchange/content.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md b/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md index 477d6cd652..1f2ec96f29 100644 --- a/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md +++ b/content/hardware/04.pro/boards/portenta-x8/tutorials/python-arduino-data-exchange/content.md @@ -24,7 +24,7 @@ The container infrastructure provided by Arduino contains a pre-built Python ima - [Portenta X8](https://store.arduino.cc/products/portenta-x8) board - [Portenta breakout](https://docs.arduino.cc/hardware/portenta-breakout) board -- Any sensor (in this example we'll use an [BME680](https://www.bosch-sensortec.com/products/environmental-sensors/gas-sensors/bme680/) I2C module) +- Any sensor (in this example we'll use an [BME680](https://www.bosch-sensortec.com/products/environmental-sensors/gas-sensors/bme680/) I2C module) ## Python on the X8 @@ -57,7 +57,7 @@ Two additional header files need to be included: The bind function makes the data available via the specified name e.g. "temperature". In our example an anonymous function is created that returns the corresponding sensor property whenever requested. Alternatively you could bind the name to an existing, named function instead. The data can then easily be requested using that name (e.g. "humidity") by querying the `m4-proxy` service. Once data is being requested it is packaged as a message and sent over SPI to the iMX8. -You can find the sketch in the software package [here](assets/python-sensor-rpc.zip). You may need to change the sketch depending on what sensor you would like to read from. If you're using an I2C sensor, you can connect SCL to **PWM6** and SDA to **PWM8** on the Portenta breakout. That's because the labeled I2C pins on the Portenta Breakout are only available on the Linux side. If you're using an analog sensor you can connect it to any analog pin. Please refer to the pinout diagram on the Portenta Breakout [documentation page](/hardware/portenta-breakout). +You can find the sketch in the software package [here](assets/python-sensor-rpc.zip). You may need to change the sketch depending on what sensor you would like to read from. If you're using an I2C sensor, you can connect SCL to **PWM6** and SDA to **PWM8** on the Portenta breakout. That's because the labeled I2C pins on the Portenta Breakout are only available on the Linux side. If you're using an analog sensor you can connect it to any analog pin. Please refer to the pinout diagram on the Portenta Breakout [documentation page](/hardware/portenta-breakout). Make sure you've installed the "Arduino Mbed OS Portenta Boards" core and upload the sketch to the X8 in the Arduino IDE or via Arduino CLI.