{ "version": "https://jsonfeed.org/version/1.1", "user_comment": "This feed allows you to read the posts from this site in any feed reader that supports the JSON Feed format. To add this feed to your reader, copy the following URL -- https://eloquentarduino.github.io/category/programming/eloquent-library/feed/json/ -- and add it your reader.", "home_page_url": "https://eloquentarduino.github.io/category/programming/eloquent-library/", "feed_url": "https://eloquentarduino.github.io/category/programming/eloquent-library/feed/json/", "language": "en-US", "title": "Eloquent library – Eloquent Arduino Blog", "description": "Machine learning on Arduino, programming & electronics", "items": [ { "id": "https://eloquentarduino.github.io/?p=1390", "url": "https://eloquentarduino.github.io/2020/12/esp32-cam-motion-detection-with-photo-capture-grayscale-version/", "title": "Esp32-cam motion detection WITH PHOTO CAPTURE! (grayscale version)", "content_html": "
Do you want to transform your cheap esp32-cam in a DIY surveillance camera with moton detection AND photo capture?
\nLook no further: this post explains STEP-BY-STEP all you need to know to build one yourself!
\n\n\n
As I told you in the Easier, faster pure video Esp32-cam motion detection post, motion detection on the esp32-cam seems to be the hottest topic on my blog, so I thought it deserved some more tutorials.
\nWithout question, to #1 request you made me in the comments was
\n\n\nHow can I save the image that triggered the motion detection to the disk?
\n
Well, in this post I will show you how to save the image to the SPIFFS filesystem your esp32-cam comes equipped with!
\nPlease read the post on easier, faster esp32-cam motion detection first if you want to understand the following code.
\nIt took me quite some time to write this post because I was struggling to design a clear, easy to use API for the motion detection feature and the image storage.
\nAnd I have to admit that, even after so long, I'm still not satisfied with the results.
\nNonetheless, it works, and it works well in my opinion, so I will publish this and maybe get feedback from you to help me improve (so please leave a comment if you have any suggestion).
\nI won't bother you with the design considerations I took since this is an hands-on tutorial, so let's take a look at the code to implement motion detection on the esp32-cam or any other esp32 with a camera attached (I'm using the M5Stick camera).
\nFirst of all, you need the EloquentVision
library: you can install it either from Github or using the Arduino IDE's Library Manager.
Next, the code.
\n// Change according to your model\n// The models available are\n// - CAMERA_MODEL_WROVER_KIT\n// - CAMERA_MODEL_ESP_EYE\n// - CAMERA_MODEL_M5STACK_PSRAM\n// - CAMERA_MODEL_M5STACK_WIDE\n// - CAMERA_MODEL_AI_THINKER\n#define CAMERA_MODEL_M5STACK_WIDE\n\n#include <FS.h>\n#include <SPIFFS.h>\n#include "EloquentVision.h"\n\n// set the resolution of the source image and the resolution of the downscaled image for the motion detection\n#define FRAME_SIZE FRAMESIZE_QVGA\n#define SOURCE_WIDTH 320\n#define SOURCE_HEIGHT 240\n#define CHANNELS 1\n#define DEST_WIDTH 32\n#define DEST_HEIGHT 24\n#define BLOCK_VARIATION_THRESHOLD 0.3\n#define MOTION_THRESHOLD 0.2\n\n// we're using the Eloquent::Vision namespace a lot!\nusing namespace Eloquent::Vision;\nusing namespace Eloquent::Vision::IO;\nusing namespace Eloquent::Vision::ImageProcessing;\nusing namespace Eloquent::Vision::ImageProcessing::Downscale;\nusing namespace Eloquent::Vision::ImageProcessing::DownscaleStrategies;\n\n// an easy interface to capture images from the camera\nESP32Camera camera;\n// the buffer to store the downscaled version of the image\nuint8_t resized[DEST_HEIGHT][DEST_WIDTH];\n// the downscaler algorithm\n// for more details see https://eloquentarduino.github.io/2020/05/easier-faster-pure-video-esp32-cam-motion-detection\nCross<SOURCE_WIDTH, SOURCE_HEIGHT, DEST_WIDTH, DEST_HEIGHT> crossStrategy;\n// the downscaler container\nDownscaler<SOURCE_WIDTH, SOURCE_HEIGHT, CHANNELS, DEST_WIDTH, DEST_HEIGHT> downscaler(&crossStrategy);\n// the motion detection algorithm\nMotionDetection<DEST_WIDTH, DEST_HEIGHT> motion;\n\nvoid setup() {\n Serial.begin(115200);\n SPIFFS.begin(true);\n camera.begin(FRAME_SIZE, PIXFORMAT_GRAYSCALE);\n motion.setBlockVariationThreshold(BLOCK_VARIATION_THRESHOLD);\n}\n\nvoid loop() {\n camera_fb_t *frame = camera.capture();\n\n // resize image and detect motion\n downscaler.downscale(frame->buf, resized);\n motion.update(resized);\n motion.detect();\n\n if (motion.ratio() > MOTION_THRESHOLD) {\n Serial.println("Motion detected");\n\n // here we want to save the image to disk\n }\n}
\nFine, we can detect motion!
\nNow we want to save the triggering image to disk in a format that we can decode without any custom software. It would be cool if we could see the image using the native Esp32 Filesystem Browser sketch.
\nThankfully to the guys at espressif, the esp32 is able to encode a raw image to JPEG format: it is convenient to use (any PC on earth can read a jpeg) and it is also fast.
\nand thanks to the reader ankaiser for pointing it out
\nIt's really easy to do thanks to the EloquentVision library.
\nif (motion.ratio() > MOTION_THRESHOLD) {\n Serial.println("Motion detected");\n\n // quality ranges from 10 to 64 -> the higher, the more detailed\n uint8_t quality = 30;\n JpegWriter<SOURCE_WIDTH, SOURCE_HEIGHT> jpegWriter;\n File imageFile = SPIFFS.open("/capture.jpg", "wb");\n\n // it takes < 1 second for a 320x240 image and 4 Kb of space\n jpegWriter.writeGrayscale(imageFile, frame->buf, quality);\n imageFile.close();\n}
\nWell done! Now your image is on the disk and can be downloaded with the FSBrowser sketch.
\nNow you have all the tools you need to create your own DIY surveillance camera with motion detection feature!
\nYou can use it to catch thieves (I discourage you to rely on such a rudimentary setup however!), to capture images of wild animals in your garden (birds, sqirrels or the like), or any other application you see fit.
\nOf course you may well understand that a proper motion detection setup should be more complex than the one presented here. Nevertheless, a couple of quick fixes can greatly improve the usability of this project with little effort. Here I suggest you a couple.
\n#1: Debouncing successive frames: the code presented in this post is a stripped down version of a more complete esp32-cam motion detection example sketch.
\nThat sketch implements a debouncing function to prevent writing "ghost images" (see the original post on motion detection for a clear evidence of this effect).
\n#2: Proper file naming: the example sketch uses a fixed filename for the image. This means any new image will overwrite the older, which may be undesiderable based on your requirements. A proper way to handle this would be to attach an RTC and name the image after the time it occurred (something like "motion_2020-12-03_08:09:10.bmp")
\n#3: RGB images: this is something I'm working on. I mean, the Bitmap writer is there (so you could actually use it to store images on your esp32), but the multi-channel motion detection is driving me crazy, I need some more time to design it the way I want, so stay tuned!
\nI hope you enjoyed this tutorial on esp32-cam motion detection with photo capture: it was born as a response to your asking, so don't be afraid and ask me anything: I will do my best to help you!
\nL'articolo Esp32-cam motion detection WITH PHOTO CAPTURE! (grayscale version) proviene da Eloquent Arduino Blog.
\n", "content_text": "Do you want to transform your cheap esp32-cam in a DIY surveillance camera with moton detection AND photo capture?\nLook no further: this post explains STEP-BY-STEP all you need to know to build one yourself!\n\n\nAs I told you in the Easier, faster pure video Esp32-cam motion detection post, motion detection on the esp32-cam seems to be the hottest topic on my blog, so I thought it deserved some more tutorials.\nWithout question, to #1 request you made me in the comments was\n\nHow can I save the image that triggered the motion detection to the disk?\n\nWell, in this post I will show you how to save the image to the SPIFFS filesystem your esp32-cam comes equipped with!\nMotion detection, refactored\nPlease read the post on easier, faster esp32-cam motion detection first if you want to understand the following code.\nIt took me quite some time to write this post because I was struggling to design a clear, easy to use API for the motion detection feature and the image storage.\nAnd I have to admit that, even after so long, I'm still not satisfied with the results.\nNonetheless, it works, and it works well in my opinion, so I will publish this and maybe get feedback from you to help me improve (so please leave a comment if you have any suggestion).\nI won't bother you with the design considerations I took since this is an hands-on tutorial, so let's take a look at the code to implement motion detection on the esp32-cam or any other esp32 with a camera attached (I'm using the M5Stick camera).\nFirst of all, you need the EloquentVision library: you can install it either from Github or using the Arduino IDE's Library Manager.\nNext, the code.\n// Change according to your model\n// The models available are\n// - CAMERA_MODEL_WROVER_KIT\n// - CAMERA_MODEL_ESP_EYE\n// - CAMERA_MODEL_M5STACK_PSRAM\n// - CAMERA_MODEL_M5STACK_WIDE\n// - CAMERA_MODEL_AI_THINKER\n#define CAMERA_MODEL_M5STACK_WIDE\n\n#include <FS.h>\n#include <SPIFFS.h>\n#include "EloquentVision.h"\n\n// set the resolution of the source image and the resolution of the downscaled image for the motion detection\n#define FRAME_SIZE FRAMESIZE_QVGA\n#define SOURCE_WIDTH 320\n#define SOURCE_HEIGHT 240\n#define CHANNELS 1\n#define DEST_WIDTH 32\n#define DEST_HEIGHT 24\n#define BLOCK_VARIATION_THRESHOLD 0.3\n#define MOTION_THRESHOLD 0.2\n\n// we're using the Eloquent::Vision namespace a lot!\nusing namespace Eloquent::Vision;\nusing namespace Eloquent::Vision::IO;\nusing namespace Eloquent::Vision::ImageProcessing;\nusing namespace Eloquent::Vision::ImageProcessing::Downscale;\nusing namespace Eloquent::Vision::ImageProcessing::DownscaleStrategies;\n\n// an easy interface to capture images from the camera\nESP32Camera camera;\n// the buffer to store the downscaled version of the image\nuint8_t resized[DEST_HEIGHT][DEST_WIDTH];\n// the downscaler algorithm\n// for more details see https://eloquentarduino.github.io/2020/05/easier-faster-pure-video-esp32-cam-motion-detection\nCross<SOURCE_WIDTH, SOURCE_HEIGHT, DEST_WIDTH, DEST_HEIGHT> crossStrategy;\n// the downscaler container\nDownscaler<SOURCE_WIDTH, SOURCE_HEIGHT, CHANNELS, DEST_WIDTH, DEST_HEIGHT> downscaler(&crossStrategy);\n// the motion detection algorithm\nMotionDetection<DEST_WIDTH, DEST_HEIGHT> motion;\n\nvoid setup() {\n Serial.begin(115200);\n SPIFFS.begin(true);\n camera.begin(FRAME_SIZE, PIXFORMAT_GRAYSCALE);\n motion.setBlockVariationThreshold(BLOCK_VARIATION_THRESHOLD);\n}\n\nvoid loop() {\n camera_fb_t *frame = camera.capture();\n\n // resize image and detect motion\n downscaler.downscale(frame->buf, resized);\n motion.update(resized);\n motion.detect();\n\n if (motion.ratio() > MOTION_THRESHOLD) {\n Serial.println("Motion detected");\n\n // here we want to save the image to disk\n }\n}\nSave image to disk\nFine, we can detect motion!\nNow we want to save the triggering image to disk in a format that we can decode without any custom software. It would be cool if we could see the image using the native Esp32 Filesystem Browser sketch.\nThankfully to the guys at espressif, the esp32 is able to encode a raw image to JPEG format: it is convenient to use (any PC on earth can read a jpeg) and it is also fast.\nand thanks to the reader ankaiser for pointing it out\nIt's really easy to do thanks to the EloquentVision library.\nif (motion.ratio() > MOTION_THRESHOLD) {\n Serial.println("Motion detected");\n\n // quality ranges from 10 to 64 -> the higher, the more detailed\n uint8_t quality = 30;\n JpegWriter<SOURCE_WIDTH, SOURCE_HEIGHT> jpegWriter;\n File imageFile = SPIFFS.open("/capture.jpg", "wb");\n\n // it takes < 1 second for a 320x240 image and 4 Kb of space\n jpegWriter.writeGrayscale(imageFile, frame->buf, quality);\n imageFile.close();\n}\nWell done! Now your image is on the disk and can be downloaded with the FSBrowser sketch.\nNow you have all the tools you need to create your own DIY surveillance camera with motion detection feature!\nYou can use it to catch thieves (I discourage you to rely on such a rudimentary setup however!), to capture images of wild animals in your garden (birds, sqirrels or the like), or any other application you see fit.\nFurther improvements\nOf course you may well understand that a proper motion detection setup should be more complex than the one presented here. Nevertheless, a couple of quick fixes can greatly improve the usability of this project with little effort. Here I suggest you a couple.\n#1: Debouncing successive frames: the code presented in this post is a stripped down version of a more complete esp32-cam motion detection example sketch.\nThat sketch implements a debouncing function to prevent writing "ghost images" (see the original post on motion detection for a clear evidence of this effect).\n#2: Proper file naming: the example sketch uses a fixed filename for the image. This means any new image will overwrite the older, which may be undesiderable based on your requirements. A proper way to handle this would be to attach an RTC and name the image after the time it occurred (something like "motion_2020-12-03_08:09:10.bmp")\n#3: RGB images: this is something I'm working on. I mean, the Bitmap writer is there (so you could actually use it to store images on your esp32), but the multi-channel motion detection is driving me crazy, I need some more time to design it the way I want, so stay tuned!\n\nI hope you enjoyed this tutorial on esp32-cam motion detection with photo capture: it was born as a response to your asking, so don't be afraid and ask me anything: I will do my best to help you!\nL'articolo Esp32-cam motion detection WITH PHOTO CAPTURE! (grayscale version) proviene da Eloquent Arduino Blog.", "date_published": "2020-12-03T18:50:59+01:00", "date_modified": "2020-12-06T09:31:20+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "Computer vision", "Eloquent library" ] }, { "id": "https://eloquentarduino.github.io/?p=1203", "url": "https://eloquentarduino.github.io/2020/06/easy-esp32-camera-http-video-streaming-server/", "title": "Easy ESP32 camera HTTP video streaming server", "content_html": "This will be a short post where I introduce a new addition to the Arduino Eloquent library aimed to make video streaming from an ESP32 camera over HTTP super easy. It will be the first component of a larger project I'm going to implement.
\n\n
If you Google "esp32 video streaming" you will get a bunch of results that are essentialy copy-pasted from the official Espressif repo: many of them neither copy-pasted the code, just tell you to load the example sketch.
\nAnd if you try to read it and try to modify just a bit for your own use-case, you won't understand much.
\nThis is the exact environment for an Eloquent component to live: make it painfully easy what's messy.
\nI still have to find a good naming scheme for my libraries since Arduino IDE doesn't allow nested imports, so forgive me if "ESP32CameraHTTPVideoStreamingServer.h" was the best that came to mind.
\nHow easy is it to use?
\n1 line of code if used in conjuction with my other library EloquentVision.
\n#define CAMERA_MODEL_M5STACK_WIDE\n#include "WiFi.h"\n#include "EloquentVision.h"\n#include "ESP32CameraHTTPVideoStreamingServer.h"\n\nusing namespace Eloquent::Vision;\nusing namespace Eloquent::Vision::Camera;\n\nESP32Camera camera;\nHTTPVideoStreamingServer server(81);\n\n/**\n *\n */\nvoid setup() {\n Serial.begin(115200);\n WiFi.softAP("ESP32", "12345678");\n\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_JPEG);\n server.start();\n\n Serial.print("Camera Ready! Use 'http://");\n Serial.print(WiFi.softAPIP());\n Serial.println(":81' to stream");\n}\n\nvoid loop() {\n}
\nHTTPVideoStreamingServer
assumes you already initialized your camera. You can achieve this task in the way you prefer: ESP32Camera
class makes this a breeze.
81
in the server constructor is the port you want the server to be listening to.
Once connected to WiFi or started in AP mode, all you have to do is call start()
: that's it!
What else is it good for?
\nThe main reason I wrote this piece of library is because one of you reader commented on the motion detection post asking if it would be possible to start the video streaming once motion is detected.
\nOf course it is.
\nIt's just a matter of composing the Eloquent pieces.
\n// not workings AS-IS, needs refactoring\n\n#define CAMERA_MODEL_M5STACK_WIDE\n#include "WiFi.h"\n#include "EloquentVision.h"\n#include "ESP32CameraHTTPVideoStreamingServer.h"\n\n#define FRAME_SIZE FRAMESIZE_QVGA\n#define SOURCE_WIDTH 320\n#define SOURCE_HEIGHT 240\n#define CHANNELS 1\n#define DEST_WIDTH 32\n#define DEST_HEIGHT 24\n#define BLOCK_VARIATION_THRESHOLD 0.3\n#define MOTION_THRESHOLD 0.2\n\n// we're using the Eloquent::Vision namespace a lot!\nusing namespace Eloquent::Vision;\nusing namespace Eloquent::Vision::Camera;\nusing namespace Eloquent::Vision::ImageProcessing;\nusing namespace Eloquent::Vision::ImageProcessing::Downscale;\nusing namespace Eloquent::Vision::ImageProcessing::DownscaleStrategies;\n\nESP32Camera camera;\nHTTPVideoStreamingServer server(81);\n// the buffer to store the downscaled version of the image\nuint8_t resized[DEST_HEIGHT][DEST_WIDTH];\n// the downscaler algorithm\n// for more details see https://eloquentarduino.github.io/2020/05/easier-faster-pure-video-esp32-cam-motion-detection\nCross<SOURCE_WIDTH, SOURCE_HEIGHT, DEST_WIDTH, DEST_HEIGHT> crossStrategy;\n// the downscaler container\nDownscaler<SOURCE_WIDTH, SOURCE_HEIGHT, CHANNELS, DEST_WIDTH, DEST_HEIGHT> downscaler(&crossStrategy);\n// the motion detection algorithm\nMotionDetection<DEST_WIDTH, DEST_HEIGHT> motion;\n\n/**\n *\n */\nvoid setup() {\n Serial.begin(115200);\n WiFi.softAP("ESP32", "12345678");\n\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_GRAYSCALE);\n motion.setBlockVariationThreshold(BLOCK_VARIATION_THRESHOLD);\n\n Serial.print("Camera Ready! Use 'http://");\n Serial.print(WiFi.softAPIP());\n Serial.println(":81' to stream");\n}\n\nvoid loop() {\n camera_fb_t *frame = camera.capture();\n\n // resize image and detect motion\n downscaler.downscale(frame->buf, resized);\n motion.update(resized);\n motion.detect();\n\n if (motion.ratio() > MOTION_THRESHOLD) {\n Serial.print("Motion detected");\n // start the streaming server when motion is detected\n // shutdown after 20 seconds if no one connects\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_JPEG);\n delay(2000);\n Serial.print("Camera Server ready! Use 'http://");\n Serial.print(WiFi.softAPIP());\n Serial.println(":81' to stream");\n server.start();\n delay(20000);\n server.stop();\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_GRAYSCALE);\n delay(2000);\n }\n\n // probably we don't need 30 fps, save some power\n delay(300);\n}
\nDoes it look good?
\nNow the rationale behind Eloquent components should be starting to be clear to you: easy to use objects you can compose the way it fits to achieve the result you want.
\nWould you suggest me more piece of functionality you would like to see wrapped in an Eloquent component?
\nYou can find the class code and the example sketch on the Github repo.
\nL'articolo Easy ESP32 camera HTTP video streaming server proviene da Eloquent Arduino Blog.
\n", "content_text": "This will be a short post where I introduce a new addition to the Arduino Eloquent library aimed to make video streaming from an ESP32 camera over HTTP super easy. It will be the first component of a larger project I'm going to implement.\n\nIf you Google "esp32 video streaming" you will get a bunch of results that are essentialy copy-pasted from the official Espressif repo: many of them neither copy-pasted the code, just tell you to load the example sketch.\nAnd if you try to read it and try to modify just a bit for your own use-case, you won't understand much.\nThis is the exact environment for an Eloquent component to live: make it painfully easy what's messy.\nI still have to find a good naming scheme for my libraries since Arduino IDE doesn't allow nested imports, so forgive me if "ESP32CameraHTTPVideoStreamingServer.h" was the best that came to mind.\nHow easy is it to use?\n1 line of code if used in conjuction with my other library EloquentVision.\n#define CAMERA_MODEL_M5STACK_WIDE\n#include "WiFi.h"\n#include "EloquentVision.h"\n#include "ESP32CameraHTTPVideoStreamingServer.h"\n\nusing namespace Eloquent::Vision;\nusing namespace Eloquent::Vision::Camera;\n\nESP32Camera camera;\nHTTPVideoStreamingServer server(81);\n\n/**\n *\n */\nvoid setup() {\n Serial.begin(115200);\n WiFi.softAP("ESP32", "12345678");\n\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_JPEG);\n server.start();\n\n Serial.print("Camera Ready! Use 'http://");\n Serial.print(WiFi.softAPIP());\n Serial.println(":81' to stream");\n}\n\nvoid loop() {\n}\nHTTPVideoStreamingServer assumes you already initialized your camera. You can achieve this task in the way you prefer: ESP32Camera class makes this a breeze.\n81 in the server constructor is the port you want the server to be listening to.\nOnce connected to WiFi or started in AP mode, all you have to do is call start(): that's it!\n\r\n\r\n\r\n \r\n\tFinding this content useful?\r\n\r\n\t\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t \r\n \r\n \r\n \r\n\r\n\r\n\r\n\nWhat else is it good for?\nThe main reason I wrote this piece of library is because one of you reader commented on the motion detection post asking if it would be possible to start the video streaming once motion is detected.\nOf course it is.\nIt's just a matter of composing the Eloquent pieces.\n// not workings AS-IS, needs refactoring\n\n#define CAMERA_MODEL_M5STACK_WIDE\n#include "WiFi.h"\n#include "EloquentVision.h"\n#include "ESP32CameraHTTPVideoStreamingServer.h"\n\n#define FRAME_SIZE FRAMESIZE_QVGA\n#define SOURCE_WIDTH 320\n#define SOURCE_HEIGHT 240\n#define CHANNELS 1\n#define DEST_WIDTH 32\n#define DEST_HEIGHT 24\n#define BLOCK_VARIATION_THRESHOLD 0.3\n#define MOTION_THRESHOLD 0.2\n\n// we're using the Eloquent::Vision namespace a lot!\nusing namespace Eloquent::Vision;\nusing namespace Eloquent::Vision::Camera;\nusing namespace Eloquent::Vision::ImageProcessing;\nusing namespace Eloquent::Vision::ImageProcessing::Downscale;\nusing namespace Eloquent::Vision::ImageProcessing::DownscaleStrategies;\n\nESP32Camera camera;\nHTTPVideoStreamingServer server(81);\n// the buffer to store the downscaled version of the image\nuint8_t resized[DEST_HEIGHT][DEST_WIDTH];\n// the downscaler algorithm\n// for more details see https://eloquentarduino.github.io/2020/05/easier-faster-pure-video-esp32-cam-motion-detection\nCross<SOURCE_WIDTH, SOURCE_HEIGHT, DEST_WIDTH, DEST_HEIGHT> crossStrategy;\n// the downscaler container\nDownscaler<SOURCE_WIDTH, SOURCE_HEIGHT, CHANNELS, DEST_WIDTH, DEST_HEIGHT> downscaler(&crossStrategy);\n// the motion detection algorithm\nMotionDetection<DEST_WIDTH, DEST_HEIGHT> motion;\n\n/**\n *\n */\nvoid setup() {\n Serial.begin(115200);\n WiFi.softAP("ESP32", "12345678");\n\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_GRAYSCALE);\n motion.setBlockVariationThreshold(BLOCK_VARIATION_THRESHOLD);\n\n Serial.print("Camera Ready! Use 'http://");\n Serial.print(WiFi.softAPIP());\n Serial.println(":81' to stream");\n}\n\nvoid loop() {\n camera_fb_t *frame = camera.capture();\n\n // resize image and detect motion\n downscaler.downscale(frame->buf, resized);\n motion.update(resized);\n motion.detect();\n\n if (motion.ratio() > MOTION_THRESHOLD) {\n Serial.print("Motion detected");\n // start the streaming server when motion is detected\n // shutdown after 20 seconds if no one connects\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_JPEG);\n delay(2000);\n Serial.print("Camera Server ready! Use 'http://");\n Serial.print(WiFi.softAPIP());\n Serial.println(":81' to stream");\n server.start();\n delay(20000);\n server.stop();\n camera.begin(FRAMESIZE_QVGA, PIXFORMAT_GRAYSCALE);\n delay(2000);\n }\n\n // probably we don't need 30 fps, save some power\n delay(300);\n}\nDoes it look good?\nNow the rationale behind Eloquent components should be starting to be clear to you: easy to use objects you can compose the way it fits to achieve the result you want.\nWould you suggest me more piece of functionality you would like to see wrapped in an Eloquent component?\n\nYou can find the class code and the example sketch on the Github repo.\nL'articolo Easy ESP32 camera HTTP video streaming server proviene da Eloquent Arduino Blog.", "date_published": "2020-06-24T19:27:33+02:00", "date_modified": "2020-12-16T21:29:52+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "camera", "esp32", "Eloquent library" ] }, { "id": "https://eloquentarduino.github.io/?p=956", "url": "https://eloquentarduino.github.io/2020/02/easy-arduino-thermal-camera-with-ascii-video-streaming/", "title": "Easy Arduino thermal camera with (ASCII) video streaming", "content_html": "Ever wanted to use your thermal camera with Arduino but found it difficult to go beyond the tutorials code? Let's see the easiest possible way to view your thermal camera streaming without an LCD display!
\n\n\n
For Arduino there are essentially two thermal camera available: the AMG8833 and the MLX90640.
\nThe AMG8833 is 8x8 and the MLX90640 is 32x24.
\nThey're not cheap, it is true.
\nBut if you have to spend money, I strongly advise you to buy the MLX90640: I have one and it's not that accurate. I can't imagine how low definition would be the AMG8833.
\nIf you want to actually get something meaningful from the camera, the AMG8833 won't give you any good results.
\nSure, you can do interpolation: interpolation would give you the impression you have a better definition, but you're just "inventing" values you don't actually have.
\nFor demo projects it could be enough. But for any serious application, spend 20$ more and buy an MLX90640.
\nAs you may know if you read my previous posts, I strongly believe in "eloquent" code, that is code that's as easy as possible to read.
\nHow many lines do you think you need to read a MLX90640 camera? Well, not that much in fact.
\n#include "EloquentMLX90640.h"\n\nusing namespace Eloquent::Sensors;\n\nfloat buffer[768];\nMLX90640 camera;\n\nvoid setup() {\n Serial.begin(115200);\n\n if (!camera.begin()) {\n Serial.println("Init error");\n delay(50000);\n }\n}\n\nvoid loop() {\n camera.read(buffer);\n delay(3000);\n}
\nIf you skip the declaration lines, you only need a begin()
and read()
call.
That's it.
\nWhat begin()
does is to run all of the boilerplate code I mentioned earlier (checking the connection and initializing the parameters).
read()
populates the buffer you pass as argument with the temperature readings.
From now on, you're free to handle that array as you may like: this is the most flexible way for the library to handle any use-case. It simply does not pose any restriction.
\nYou can find the camera code at the end of the page or on Github.
\nNow that you have this data, you may want to actually "view" it. Well, that's not an easy task as one may hope.
\nYou will need an LCD if you want to create a standalone product. If you have one, it'll be the best, it's a really cute project to build.
\nHere's a video from Adafruit that showcases even a 3D-printed case.
\n\nIf you don't have an LCD, though, it is less practical to access your image.
\nI did this in the past, and it meant creating a Python script reading the serial port every second and updating a plot.
\nIt works, sure, but it's not the most convenient way to handle it.
This is the reason I thought about ASCII art: it is used to draw images in plain text, so you can view them directly in the serial monitor.
\nOf course they will not be as accurate or representative as RGB images, but can give you an idea of what you're framing in realtime.
\nI wrote a class to do this. Once imported in your sketch, it is super easy to get it working.
\n#include "EloquentAsciiArt.h"\n\nusing namespace Eloquent::ImageProcessing;\n\nfloat buffer[768];\nuint8_t bufferBytes[768];\nMLX90640 camera;\n// we need to specify width and height of the image\nAsciiArt<32, 24> art(bufferBytes);\n\nvoid loop() {\n camera.read(buffer);\n\n // convert float image to uint8\n for (size_t i = 0; i < 768; i++) {\n // assumes readings are in the range 0-40 degrees\n // change as per your need\n bufferBytes[i] = map(buffer[i], 0, 40, 0, 255);\n }\n\n // print to Serial with a border of 2 characters, to distinguish one image from the next\n art.print(&Serial, 2);\n delay(2000);\n}
\nAs you can see, you need to create an AsciiArt
object, map the image pixels in the range 0-255
and call the print()
method: easy peasy!
You can find the ASCII art generator code at the end of the page or on Github.
\nHere's the result of the sketch. It's a video of me putting my arms at the top of my head, once at a time, then standing up.
\nOf course the visual effect won't be as impressive as an RGB image, but you can clearly see my figure moving.
\nThe real bad part is the "glitch" you see between each frame when the scrolling happens: this is something I don't know if it's possible to mitigate.
\nCheck the full project code on Github
\n#pragma once\n\n#include "Wire.h"\n#include "MLX90640_API.h"\n#include "MLX90640_I2C_Driver.h"\n\n#ifndef TA_SHIFT\n//Default shift for MLX90640 in open air\n#define TA_SHIFT 8\n#endif\n\nnamespace Eloquent {\n namespace Sensors {\n\n enum class MLX90640Status {\n OK,\n NOT_CONNECTED,\n DUMP_ERROR,\n PARAMETER_ERROR,\n FRAME_ERROR\n };\n\n class MLX90640 {\n public:\n /**\n *\n * @param address\n */\n MLX90640(uint8_t address = 0x33) :\n _address(address),\n _status(MLX90640Status::OK) {\n\n }\n\n /**\n *\n * @return\n */\n bool begin() {\n Wire.begin();\n Wire.setClock(400000);\n\n return isConnected() && loadParams();\n }\n\n /**\n *\n * @return\n */\n bool read(float result[768]) {\n for (byte x = 0 ; x < 2 ; x++) {\n uint16_t frame[834];\n int status = MLX90640_GetFrameData(_address, frame);\n\n if (status < 0)\n return fail(MLX90640Status::FRAME_ERROR);\n\n float vdd = MLX90640_GetVdd(frame, &_params);\n float Ta = MLX90640_GetTa(frame, &_params);\n float tr = Ta - TA_SHIFT;\n float emissivity = 0.95;\n\n MLX90640_CalculateTo(frame, &_params, emissivity, tr, result);\n }\n }\n\n protected:\n uint8_t _address;\n paramsMLX90640 _params;\n MLX90640Status _status;\n\n /**\n * Test if device is connected\n * @return\n */\n bool isConnected() {\n Wire.beginTransmission(_address);\n\n if (Wire.endTransmission() == 0) {\n return true;\n }\n\n return fail(MLX90640Status::NOT_CONNECTED);\n }\n\n /**\n *\n * @return\n */\n bool loadParams() {\n uint16_t ee[832];\n int status = MLX90640_DumpEE(_address, ee);\n\n if (status != 0)\n return fail(MLX90640Status::DUMP_ERROR);\n\n status = MLX90640_ExtractParameters(ee, &_params);\n\n if (status != 0)\n return fail(MLX90640Status::PARAMETER_ERROR);\n\n return true;\n }\n\n /**\n * Mark a failure\n * @param status\n * @return\n */\n bool fail(MLX90640Status status) {\n _status = status;\n\n return false;\n }\n };\n }\n}
\n\n#pragma once\n\n#include "Stream.h"\n\nnamespace Eloquent {\n namespace ImageProcessing {\n\n /**\n *\n * @tparam width\n * @tparam height\n */\n template<size_t width, size_t height>\n class AsciiArt {\n public:\n AsciiArt(const uint8_t *data) {\n _data = data;\n }\n\n /**\n * Get pixel at given coordinates\n * @param x\n * @param y\n * @return\n */\n uint8_t at(size_t x, size_t y) {\n return _data[y * width + x];\n }\n\n /**\n * Print as ASCII art picture\n * @param stream\n */\n void print(Stream *stream, uint8_t frameSize = 0) {\n const char glyphs[] = " .,:;xyYX";\n const uint8_t glyphsCount = 9;\n\n printAsciiArtHorizontalFrame(stream, frameSize);\n\n for (size_t y = 0; y < height; y++) {\n // vertical frame\n for (uint8_t k = 0; k < frameSize; k++)\n Serial.print('|');\n\n for (size_t x = 0; x < width; x++) {\n const uint8_t glyph = floor(((uint16_t) at(x, y)) * glyphsCount / 256);\n\n stream->print(glyphs[glyph]);\n }\n\n // vertical frame\n for (uint8_t k = 0; k < frameSize; k++)\n Serial.print('|');\n\n stream->print('\\n');\n }\n\n printAsciiArtHorizontalFrame(stream, frameSize);\n stream->flush();\n }\n\n protected:\n const uint8_t *_data;\n\n /**\n *\n * @param stream\n * @param frameSize\n */\n void printAsciiArtHorizontalFrame(Stream *stream, uint8_t frameSize) {\n for (uint8_t i = 0; i < frameSize; i++) {\n for (size_t j = 0; j < width + 2 * frameSize; j++)\n stream->print('-');\n stream->print('\\n');\n }\n }\n };\n }\n}
\nL'articolo Easy Arduino thermal camera with (ASCII) video streaming proviene da Eloquent Arduino Blog.
\n", "content_text": "Ever wanted to use your thermal camera with Arduino but found it difficult to go beyond the tutorials code? Let's see the easiest possible way to view your thermal camera streaming without an LCD display!\n\n\nMLX90640 thermal camera\nFor Arduino there are essentially two thermal camera available: the AMG8833 and the MLX90640.\nThe AMG8833 is 8x8 and the MLX90640 is 32x24.\nThey're not cheap, it is true.\nBut if you have to spend money, I strongly advise you to buy the MLX90640: I have one and it's not that accurate. I can't imagine how low definition would be the AMG8833.\nIf you want to actually get something meaningful from the camera, the AMG8833 won't give you any good results.\nSure, you can do interpolation: interpolation would give you the impression you have a better definition, but you're just "inventing" values you don't actually have.\nFor demo projects it could be enough. But for any serious application, spend 20$ more and buy an MLX90640.\nMLX90640 eloquent library\nAs you may know if you read my previous posts, I strongly believe in "eloquent" code, that is code that's as easy as possible to read.\nHow many lines do you think you need to read a MLX90640 camera? Well, not that much in fact.\n#include "EloquentMLX90640.h"\n\nusing namespace Eloquent::Sensors;\n\nfloat buffer[768];\nMLX90640 camera;\n\nvoid setup() {\n Serial.begin(115200);\n\n if (!camera.begin()) {\n Serial.println("Init error");\n delay(50000);\n }\n}\n\nvoid loop() {\n camera.read(buffer);\n delay(3000);\n}\nIf you skip the declaration lines, you only need a begin() and read() call.\nThat's it.\nWhat begin() does is to run all of the boilerplate code I mentioned earlier (checking the connection and initializing the parameters).\nread() populates the buffer you pass as argument with the temperature readings.\nFrom now on, you're free to handle that array as you may like: this is the most flexible way for the library to handle any use-case. It simply does not pose any restriction.\nYou can find the camera code at the end of the page or on Github.\nPrinting as ASCII Art\nNow that you have this data, you may want to actually "view" it. Well, that's not an easy task as one may hope.\nYou will need an LCD if you want to create a standalone product. If you have one, it'll be the best, it's a really cute project to build.\nHere's a video from Adafruit that showcases even a 3D-printed case.\n\nIf you don't have an LCD, though, it is less practical to access your image.\nI did this in the past, and it meant creating a Python script reading the serial port every second and updating a plot.\nIt works, sure, but it's not the most convenient way to handle it.\nThis is the reason I thought about ASCII art: it is used to draw images in plain text, so you can view them directly in the serial monitor.\nOf course they will not be as accurate or representative as RGB images, but can give you an idea of what you're framing in realtime.\nI wrote a class to do this. Once imported in your sketch, it is super easy to get it working.\n#include "EloquentAsciiArt.h"\n\nusing namespace Eloquent::ImageProcessing;\n\nfloat buffer[768];\nuint8_t bufferBytes[768];\nMLX90640 camera;\n// we need to specify width and height of the image\nAsciiArt<32, 24> art(bufferBytes);\n\nvoid loop() {\n camera.read(buffer);\n\n // convert float image to uint8\n for (size_t i = 0; i < 768; i++) {\n // assumes readings are in the range 0-40 degrees\n // change as per your need\n bufferBytes[i] = map(buffer[i], 0, 40, 0, 255);\n }\n\n // print to Serial with a border of 2 characters, to distinguish one image from the next\n art.print(&Serial, 2);\n delay(2000);\n}\nAs you can see, you need to create an AsciiArt object, map the image pixels in the range 0-255 and call the print() method: easy peasy!\nYou can find the ASCII art generator code at the end of the page or on Github.\nHere's the result of the sketch. It's a video of me putting my arms at the top of my head, once at a time, then standing up.\nResize the Serial Monitor as only a single frame at a time is visble to have a \"video streaming\" effect\n\nhttps://eloquentarduino.github.io/wp-content/uploads/2020/02/Thermal-ascii-speedup.mp4\nOf course the visual effect won't be as impressive as an RGB image, but you can clearly see my figure moving.\nThe real bad part is the "glitch" you see between each frame when the scrolling happens: this is something I don't know if it's possible to mitigate.\n\r\nCheck the full project code on Github\n\n\n#pragma once\n\n#include "Wire.h"\n#include "MLX90640_API.h"\n#include "MLX90640_I2C_Driver.h"\n\n#ifndef TA_SHIFT\n//Default shift for MLX90640 in open air\n#define TA_SHIFT 8\n#endif\n\nnamespace Eloquent {\n namespace Sensors {\n\n enum class MLX90640Status {\n OK,\n NOT_CONNECTED,\n DUMP_ERROR,\n PARAMETER_ERROR,\n FRAME_ERROR\n };\n\n class MLX90640 {\n public:\n /**\n *\n * @param address\n */\n MLX90640(uint8_t address = 0x33) :\n _address(address),\n _status(MLX90640Status::OK) {\n\n }\n\n /**\n *\n * @return\n */\n bool begin() {\n Wire.begin();\n Wire.setClock(400000);\n\n return isConnected() && loadParams();\n }\n\n /**\n *\n * @return\n */\n bool read(float result[768]) {\n for (byte x = 0 ; x < 2 ; x++) {\n uint16_t frame[834];\n int status = MLX90640_GetFrameData(_address, frame);\n\n if (status < 0)\n return fail(MLX90640Status::FRAME_ERROR);\n\n float vdd = MLX90640_GetVdd(frame, &_params);\n float Ta = MLX90640_GetTa(frame, &_params);\n float tr = Ta - TA_SHIFT;\n float emissivity = 0.95;\n\n MLX90640_CalculateTo(frame, &_params, emissivity, tr, result);\n }\n }\n\n protected:\n uint8_t _address;\n paramsMLX90640 _params;\n MLX90640Status _status;\n\n /**\n * Test if device is connected\n * @return\n */\n bool isConnected() {\n Wire.beginTransmission(_address);\n\n if (Wire.endTransmission() == 0) {\n return true;\n }\n\n return fail(MLX90640Status::NOT_CONNECTED);\n }\n\n /**\n *\n * @return\n */\n bool loadParams() {\n uint16_t ee[832];\n int status = MLX90640_DumpEE(_address, ee);\n\n if (status != 0)\n return fail(MLX90640Status::DUMP_ERROR);\n\n status = MLX90640_ExtractParameters(ee, &_params);\n\n if (status != 0)\n return fail(MLX90640Status::PARAMETER_ERROR);\n\n return true;\n }\n\n /**\n * Mark a failure\n * @param status\n * @return\n */\n bool fail(MLX90640Status status) {\n _status = status;\n\n return false;\n }\n };\n }\n}\n\n#pragma once\n\n#include "Stream.h"\n\nnamespace Eloquent {\n namespace ImageProcessing {\n\n /**\n *\n * @tparam width\n * @tparam height\n */\n template<size_t width, size_t height>\n class AsciiArt {\n public:\n AsciiArt(const uint8_t *data) {\n _data = data;\n }\n\n /**\n * Get pixel at given coordinates\n * @param x\n * @param y\n * @return\n */\n uint8_t at(size_t x, size_t y) {\n return _data[y * width + x];\n }\n\n /**\n * Print as ASCII art picture\n * @param stream\n */\n void print(Stream *stream, uint8_t frameSize = 0) {\n const char glyphs[] = " .,:;xyYX";\n const uint8_t glyphsCount = 9;\n\n printAsciiArtHorizontalFrame(stream, frameSize);\n\n for (size_t y = 0; y < height; y++) {\n // vertical frame\n for (uint8_t k = 0; k < frameSize; k++)\n Serial.print('|');\n\n for (size_t x = 0; x < width; x++) {\n const uint8_t glyph = floor(((uint16_t) at(x, y)) * glyphsCount / 256);\n\n stream->print(glyphs[glyph]);\n }\n\n // vertical frame\n for (uint8_t k = 0; k < frameSize; k++)\n Serial.print('|');\n\n stream->print('\\n');\n }\n\n printAsciiArtHorizontalFrame(stream, frameSize);\n stream->flush();\n }\n\n protected:\n const uint8_t *_data;\n\n /**\n *\n * @param stream\n * @param frameSize\n */\n void printAsciiArtHorizontalFrame(Stream *stream, uint8_t frameSize) {\n for (uint8_t i = 0; i < frameSize; i++) {\n for (size_t j = 0; j < width + 2 * frameSize; j++)\n stream->print('-');\n stream->print('\\n');\n }\n }\n };\n }\n}\nL'articolo Easy Arduino thermal camera with (ASCII) video streaming proviene da Eloquent Arduino Blog.", "date_published": "2020-02-29T17:20:15+01:00", "date_modified": "2020-03-02T20:19:00+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "Computer vision", "Electronics", "Eloquent library" ], "attachments": [ { "url": "https://eloquentarduino.github.io/wp-content/uploads/2020/02/Thermal-ascii-speedup.mp4", "mime_type": "video/mp4", "size_in_bytes": 479591 } ] }, { "id": "https://eloquentarduino.github.io/?p=167", "url": "https://eloquentarduino.github.io/2019/12/arduino-pin-class/", "title": "Eloquent pin management: the Pin class", "content_html": "Pin
is a class for pin manipulation: you can read, write, turnOn, turnOff, toggle and a lot more. Please, stop writing horrible code like digitalWrite(led, HIGH)
and start writing led.turnOn()
instead.
\n
Pin
is actually an abstract class, so you won't use it directly, but through its specialized implementations:
#import <eIO.h>\n\nusing namespace Eloquent::Pin;
\nIf the namespace stuff is new to you, here I'll briefly say that it is used to avoid name collisions among different libraries. This seems to be an alien topic in the Arduino world and I can't really explain why.
\n99% of the libraries out there deal with this problem in one of two modes:
\nMPU6050.h
library, which elects itself as the only one implementation possible to access the MPU6050 accelerometer in the worldAdafruit_Si7021
classThe case for Adafruit_Si7021 should not exist in my opinion: use the damn namespaces!
Click To Tweet
With namespaces, it would become:
\nusing namespace Adafruit;\n\nSi7021 si;
\nFirst of all, all the 4 implementations accept a single constructor argument: the pin number.
\n DigitalOut led(BUILTIN_LED);\n DigitalIn pushButton(10);\n AnalogIn potentiometer(A0);\n AnalogOut pwmLed(8);
\nThen it is good practice to init your pins in the setup.
\n void setup() {\n led.begin();\n pushButton.begin();\n potentiometer.begin();\n pwmLed.begin();\n }
\nAll the 4 classes let you ask for the pin current value via the value()
method:
void test() {\n // DigitalIn returns the last read value, as 0/1\n digitalIn.value();\n\n // AnalogIn returns the last read value, in the range [0, 1024]\n analogIn.value();\n\n // DigitalOut returns the last written value, as 0/1\n digitalOut.value();\n\n // AnaloglOut returns the last written value, in the range [0, 255]\n analogOut.value();\n }
\nAt this point each class will provide its specialized methods.
\nvoid test() {\n // configure pin as INPUT_PULLUP\n pin.pullup();\n\n // configure pin as Active Low \n // that is, pin is ON when digitalRead() is LOW\n pin.activeLow();\n\n // read and update pin value\n pin.read();\n\n // test if pin is on (doesn't read the pin)\n pin.isOn();\n\n // test if pin is off (doesn't read the pin)\n pin.isOff();\n\n // test if pin value changed from last reading\n pin.changed();\n}
\nvoid test() {\n // set pin as Active Low\n // that is, turnOn writes LOW\n pin.activeLow();\n\n // turn pin on\n pin.turnOn();\n\n // turn pin off\n pin.turnOff();\n\n // toggle\n pin.toggle();\n\n // blink N times at intervals of X milliseconds\n pin.blink(N, X);\n}
\nvoid test() {\n // read current pin value\n pin.read();\n\n // get pin previous value\n pin.prev();\n\n // get difference between current value and previous\n pin.delta();\n\n // get absolute value of delta()\n pin.absDelta();\n}
\nvoid test() {\n // write value X to pin\n pin.write(X);\n}
\nIf you don't believe a whole class is worthwhile to work with pins, I'll show a few use cases to illustrate my point.
\nThe ESP8266 has a builtin LED you can control, but it is an active low one: it will turn on when you write LOW
. In this case, digitalWrite(BUILTIN_LED, LOW)
can be misleading regarding your actual intentions.
It doesn't look intuitive, it doesn't look eloquent! builtinLed.turnOn()
does, however. All you need to get it working correctly is calling builtinLed.activeLow()
once in your setup.
// BEFORE\nvoid loop() {\n // to turn the builtin LED on\n digitalWrite(led, LOW);\n}
\n// AFTER\nDigitalOut buildtinLed;\n\nvoid setup() {\n builtinLed.activeLow();\n}\n\nvoid loop() {\n // to turn the builtin LED on\n builtinLed.turnOn();\n}
\nIf you need to toggle the current state of a digital output, you need an helper variable to keep track of the state and remember to always update that variable when you write to the output.
\nWith a class, the state is tightly bound to the instance, so you have a single source of truth: turnOn()
, turnOff()
and toggle()
will take care of updating the inner state accordingly.
// BEFORE\n#define LED 1\n\nbool ledState = true;\n\nloop() {\n digitalWrite(LED, ledState);\n ledState = !ledState\n}
\n// AFTER\nDigitalOut led(1);\n\nvoid loop() {\n led.toggle();\n}
\nWhat if you have an analog input and want to know if its valued changed by at least X from your latest reading? You would need an helper variable again.
\nNow imagine if you have 5 analog inputs you want to track: you'll end up with 10 variables and of course you have again to always keep both in sync.
\nAnalogIn
conveniently provides delta()
and absDelta()
methods that give you the change from the previous reading and will always be in sync. Awesome!
// BEFORE\n#define INPUT1 A1\n#define INPUT2 A2\n\nuint16_t current1, prev1;\nuint16_t current2, prev2;\n\nvoid loop() {\n prev1 = current1;\n current1 = analogRead(INPUT1);\n prev2 = current2;\n current2 = analogRead(INPUT2);\n\n if (abs(current1 - prev1) > THRESHOLD)\n ...
\n// AFTER\nAnalogIn input1(A1), input2(A2);\n\nvoid loop() {\n input1.read();\n input2.read();\n\n if (input1.absDelta() > THRESHOLD)\n ...\n}
\nDid you find this tutorial useful? Was is it easy to follow or did I miss something? Let me know in the comments so I can keep improving the blog.
\nL'articolo Eloquent pin management: the Pin class proviene da Eloquent Arduino Blog.
\n", "content_text": "Pin is a class for pin manipulation: you can read, write, turnOn, turnOff, toggle and a lot more. Please, stop writing horrible code like digitalWrite(led, HIGH) and start writing led.turnOn() instead. \n\nPin is actually an abstract class, so you won't use it directly, but through its specialized implementations:\n\nDigitalIn\nDigitalOut\nAnalogIn\nAnalogOut\n\nImport the library\nTo follow this tutorial along you need to first install the Eloquent library\n#import <eIO.h>\n\nusing namespace Eloquent::Pin;\nIf the namespace stuff is new to you, here I'll briefly say that it is used to avoid name collisions among different libraries. This seems to be an alien topic in the Arduino world and I can't really explain why.\n99% of the libraries out there deal with this problem in one of two modes:\n\nignoring it altogether, so you have an MPU6050.h library, which elects itself as the only one implementation possible to access the MPU6050 accelerometer in the world\nprefixing each library file, so you get the Adafruit_Si7021 class\n\nThe case for Adafruit_Si7021 should not exist in my opinion: use the damn namespaces!Click To Tweet\nWith namespaces, it would become:\nusing namespace Adafruit;\n\nSi7021 si;\nHow to use\nFirst of all, all the 4 implementations accept a single constructor argument: the pin number.\n DigitalOut led(BUILTIN_LED);\n DigitalIn pushButton(10);\n AnalogIn potentiometer(A0);\n AnalogOut pwmLed(8);\nThen it is good practice to init your pins in the setup.\n void setup() {\n led.begin();\n pushButton.begin();\n potentiometer.begin();\n pwmLed.begin();\n }\nAll the 4 classes let you ask for the pin current value via the value() method:\n void test() {\n // DigitalIn returns the last read value, as 0/1\n digitalIn.value();\n\n // AnalogIn returns the last read value, in the range [0, 1024]\n analogIn.value();\n\n // DigitalOut returns the last written value, as 0/1\n digitalOut.value();\n\n // AnaloglOut returns the last written value, in the range [0, 255]\n analogOut.value();\n }\nAt this point each class will provide its specialized methods.\nDigitalIn\nvoid test() {\n // configure pin as INPUT_PULLUP\n pin.pullup();\n\n // configure pin as Active Low \n // that is, pin is ON when digitalRead() is LOW\n pin.activeLow();\n\n // read and update pin value\n pin.read();\n\n // test if pin is on (doesn't read the pin)\n pin.isOn();\n\n // test if pin is off (doesn't read the pin)\n pin.isOff();\n\n // test if pin value changed from last reading\n pin.changed();\n}\nDigitalOut\nvoid test() {\n // set pin as Active Low\n // that is, turnOn writes LOW\n pin.activeLow();\n\n // turn pin on\n pin.turnOn();\n\n // turn pin off\n pin.turnOff();\n\n // toggle\n pin.toggle();\n\n // blink N times at intervals of X milliseconds\n pin.blink(N, X);\n}\nAnalogIn\nvoid test() {\n // read current pin value\n pin.read();\n\n // get pin previous value\n pin.prev();\n\n // get difference between current value and previous\n pin.delta();\n\n // get absolute value of delta()\n pin.absDelta();\n}\nAnalogOut\nvoid test() {\n // write value X to pin\n pin.write(X);\n}\n\nIf you don't believe a whole class is worthwhile to work with pins, I'll show a few use cases to illustrate my point.\nUse case #1: active low LED\nThe ESP8266 has a builtin LED you can control, but it is an active low one: it will turn on when you write LOW. In this case, digitalWrite(BUILTIN_LED, LOW) can be misleading regarding your actual intentions. \nIt doesn't look intuitive, it doesn't look eloquent! builtinLed.turnOn() does, however. All you need to get it working correctly is calling builtinLed.activeLow() once in your setup.\n// BEFORE\nvoid loop() {\n // to turn the builtin LED on\n digitalWrite(led, LOW);\n}\n// AFTER\nDigitalOut buildtinLed;\n\nvoid setup() {\n builtinLed.activeLow();\n}\n\nvoid loop() {\n // to turn the builtin LED on\n builtinLed.turnOn();\n}\nUse case #2: toggle\nIf you need to toggle the current state of a digital output, you need an helper variable to keep track of the state and remember to always update that variable when you write to the output.\nWith a class, the state is tightly bound to the instance, so you have a single source of truth: turnOn(), turnOff() and toggle() will take care of updating the inner state accordingly.\n// BEFORE\n#define LED 1\n\nbool ledState = true;\n\nloop() {\n digitalWrite(LED, ledState);\n ledState = !ledState\n}\n// AFTER\nDigitalOut led(1);\n\nvoid loop() {\n led.toggle();\n}\nUse case #3: analog delta\nWhat if you have an analog input and want to know if its valued changed by at least X from your latest reading? You would need an helper variable again. \nNow imagine if you have 5 analog inputs you want to track: you'll end up with 10 variables and of course you have again to always keep both in sync.\nAnalogIn conveniently provides delta() and absDelta() methods that give you the change from the previous reading and will always be in sync. Awesome!\n// BEFORE\n#define INPUT1 A1\n#define INPUT2 A2\n\nuint16_t current1, prev1;\nuint16_t current2, prev2;\n\nvoid loop() {\n prev1 = current1;\n current1 = analogRead(INPUT1);\n prev2 = current2;\n current2 = analogRead(INPUT2);\n\n if (abs(current1 - prev1) > THRESHOLD)\n ...\n// AFTER\nAnalogIn input1(A1), input2(A2);\n\nvoid loop() {\n input1.read();\n input2.read();\n\n if (input1.absDelta() > THRESHOLD)\n ...\n}\nDid you find this tutorial useful? Was is it easy to follow or did I miss something? Let me know in the comments so I can keep improving the blog.\nL'articolo Eloquent pin management: the Pin class proviene da Eloquent Arduino Blog.", "date_published": "2019-12-06T17:15:13+01:00", "date_modified": "2020-01-25T17:15:54+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "Eloquent library" ] }, { "id": "https://eloquentarduino.github.io/?p=211", "url": "https://eloquentarduino.github.io/2019/12/arduino-bounded-waiting/", "title": "Eloquent bounded waiting: the await construct", "content_html": "Sometimes you may need to wait for a certain condition to become true, but you don't want to wait forever: it may be awaiting for Serial, for the Wifi to connect to a network, or the response from a SoftwareSerial peripheral. The await
construct lets you put an upper bound to the time you're willing to wait.
\n
Most often, you see example code of this kind:
\nSerial.print("Attempting to connect to WiFi");\n\nwhile (WiFi.status() != WL_CONNECTED) {\n Serial.print(".");\n delay(500);\n}
\nIf the connection doesn't succeed (maybe the AP is out of range or is down), you're stuck in an endless wait. A proper way for handling such situations is with a timeout that gets you out of the loop with an error status so you can handle the failure.
\nawait
is exactly this: a construct to await for a condition to become true until a timeout expires, returning true or false as a response.
#define await(condition, timeout) await_with_interval(condition, timeout, 10)\n#define await_with_interval(condition, timeout, interval) \\\n ([]() { \\\n uint32_t start = millis(); \\\n while (millis() - start <= timeout) { \\\n if (condition) return true; \\\n delay(interval); \\\n } \\\n return false; })()
\nawait
needs at least two arguments:
// these are for greater code readability\r\n#define Millis \r\n#define Second *1000\r\n#define Seconds *1000\r\n
\nbool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)
\nThe code above will wait 10 seconds for the wifi to connect: on failure, wifiConnected
will be false and you can gently fail.
You can use it for any kind of check, like waiting for Serial
.
bool serialReady = await(Serial, 5 Seconds)\nbool serialHasCharacters = await(Serial.available(), 5 Seconds)
\nThe default interval between checks is 10 milliseconds: if you need a custom delay interval you can use the more verbose await_with_interval
:
// await WiFi for 10 seconds, check if connected every 500 millis\nbool wifiConnected = await_with_interval(WiFi.status() == WL_CONNECTED, 10 Seconds, 500 Millis)
\nThe await
macro creates an inline function that loops until the timeout expires. At every loop it checks if the condition is true: if that's the case, it returns true. The inline function construct is needed to get a return value, so you can assign it to a variable or embed directly inside an if
test. The following code sample gives you an idea of what's happening.
bool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)\n\n// conceptually translates to\n\nbool inline_function() {\n uint32_t start = millis();\n\n while (millis() - start <= 10000) {\n if (WiFi.status() == WL_CONNECTED)\n return true;\n\n delay(10);\n }\n\n return false;\n}\n\nbool wifiConnected = inline_function();
\nL'articolo Eloquent bounded waiting: the await construct proviene da Eloquent Arduino Blog.
\n", "content_text": "Sometimes you may need to wait for a certain condition to become true, but you don't want to wait forever: it may be awaiting for Serial, for the Wifi to connect to a network, or the response from a SoftwareSerial peripheral. The await construct lets you put an upper bound to the time you're willing to wait.\n\nMost often, you see example code of this kind:\nSerial.print("Attempting to connect to WiFi");\n\nwhile (WiFi.status() != WL_CONNECTED) {\n Serial.print(".");\n delay(500);\n}\nIf the connection doesn't succeed (maybe the AP is out of range or is down), you're stuck in an endless wait. A proper way for handling such situations is with a timeout that gets you out of the loop with an error status so you can handle the failure.\nawait is exactly this: a construct to await for a condition to become true until a timeout expires, returning true or false as a response.\nDefinition\n#define await(condition, timeout) await_with_interval(condition, timeout, 10)\n#define await_with_interval(condition, timeout, interval) \\\n ([]() { \\\n uint32_t start = millis(); \\\n while (millis() - start <= timeout) { \\\n if (condition) return true; \\\n delay(interval); \\\n } \\\n return false; })()\nHow to use\nawait needs at least two arguments:\n\nthe condition to await for\nthe timeout, in milliseconds\n\n// these are for greater code readability\r\n#define Millis \r\n#define Second *1000\r\n#define Seconds *1000\r\n\nbool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)\nThe code above will wait 10 seconds for the wifi to connect: on failure, wifiConnected will be false and you can gently fail. \nYou can use it for any kind of check, like waiting for Serial.\nbool serialReady = await(Serial, 5 Seconds)\nbool serialHasCharacters = await(Serial.available(), 5 Seconds)\nThe default interval between checks is 10 milliseconds: if you need a custom delay interval you can use the more verbose await_with_interval:\n// await WiFi for 10 seconds, check if connected every 500 millis\nbool wifiConnected = await_with_interval(WiFi.status() == WL_CONNECTED, 10 Seconds, 500 Millis)\nHow it works\nThe await macro creates an inline function that loops until the timeout expires. At every loop it checks if the condition is true: if that's the case, it returns true. The inline function construct is needed to get a return value, so you can assign it to a variable or embed directly inside an if test. The following code sample gives you an idea of what's happening.\nbool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)\n\n// conceptually translates to\n\nbool inline_function() {\n uint32_t start = millis();\n\n while (millis() - start <= 10000) {\n if (WiFi.status() == WL_CONNECTED)\n return true;\n\n delay(10);\n }\n\n return false;\n}\n\nbool wifiConnected = inline_function();\nL'articolo Eloquent bounded waiting: the await construct proviene da Eloquent Arduino Blog.", "date_published": "2019-12-05T19:50:59+01:00", "date_modified": "2019-12-16T23:03:25+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "eloquent", "Eloquent library" ] }, { "id": "https://eloquentarduino.github.io/?p=209", "url": "https://eloquentarduino.github.io/2019/12/non-blocking-arduino-code/", "title": "Eloquent non-blocking code: the Every construct", "content_html": "The every
construct lets you run a piace of code at regular intervals in a fluent way. If you don't need to start, stop, pause your timer, this construct is a valid alternative to more complex timer libraries already available: it only takes a time interval as argument and will execute the code block periodically.
\n
#define every(interval) \\\n static uint32_t __every__##interval = millis(); \\\n if (millis() - __every__##interval >= interval && (__every__##interval = millis()))
\n// these are for greater code readability\r\n#define Millis \r\n#define Second *1000\r\n#define Seconds *1000\r\n
\nint interval = 1 Second;\n\nvoid setup() {\n Serial.begin(115200);\n}\n\nvoid loop() {\n every(1000 Millis) {\n Serial.println("This line is printed every 1 second");\n }\n\n every(2000 Millis) {\n Serial.println("This line is printed every 2 seconds");\n }\n\n every(interval) {\n interval += 1 Second;\n Serial.print("You can have variable intervals too! ");\n Serial.print("This line will be printed again in ");\n Serial.print(interval / 1000);\n Serial.println(" seconds");\n }\n}
\nevery
is just a macro definition and is not a proper timer, so it has some limitations:
every
with the exact same argument: you have to put all the code that needs to happen at the same interval in the same blockThe macro works by generating a variable named like __every__##argument
every(1) ==> uint32_t __every__1;\nevery(2) ==> uint32_t __every__2;\nevery(a_given_interval) ==> uint32_t __every__a_given_interval;\nevery(an invalid interval) ==> uint32_t __every__an invalid interval; // Syntax error\nevery(1 Second) ==> uint32_t __every__1 *1000; // Syntax error
\nSo every integer literal and any variable are all valid arguments. Any expression is forbidden.
\nIf you use two every
with the exact same argument, two variables with the exact same name will be created and it will rise a compile-time error.
If you can live with this limitations, every
only needs the space of an uint32_t
to work.
L'articolo Eloquent non-blocking code: the Every construct proviene da Eloquent Arduino Blog.
\n", "content_text": "The every construct lets you run a piace of code at regular intervals in a fluent way. If you don't need to start, stop, pause your timer, this construct is a valid alternative to more complex timer libraries already available: it only takes a time interval as argument and will execute the code block periodically.\n\nDefinition\n#define every(interval) \\\n static uint32_t __every__##interval = millis(); \\\n if (millis() - __every__##interval >= interval && (__every__##interval = millis()))\nHow to use\n// these are for greater code readability\r\n#define Millis \r\n#define Second *1000\r\n#define Seconds *1000\r\n\nint interval = 1 Second;\n\nvoid setup() {\n Serial.begin(115200);\n}\n\nvoid loop() {\n every(1000 Millis) {\n Serial.println("This line is printed every 1 second");\n }\n\n every(2000 Millis) {\n Serial.println("This line is printed every 2 seconds");\n }\n\n every(interval) {\n interval += 1 Second;\n Serial.print("You can have variable intervals too! ");\n Serial.print("This line will be printed again in ");\n Serial.print(interval / 1000);\n Serial.println(" seconds");\n }\n}\nCaveats\nevery is just a macro definition and is not a proper timer, so it has some limitations:\n\nyou can't stop, pause or resume it: once set, it will run forever\nits argument must be the suffix of a valid identifier\nyou can't use several every with the exact same argument: you have to put all the code that needs to happen at the same interval in the same block\n\nCaveat #2\nThe macro works by generating a variable named like __every__##argument\nevery(1) ==> uint32_t __every__1;\nevery(2) ==> uint32_t __every__2;\nevery(a_given_interval) ==> uint32_t __every__a_given_interval;\nevery(an invalid interval) ==> uint32_t __every__an invalid interval; // Syntax error\nevery(1 Second) ==> uint32_t __every__1 *1000; // Syntax error\nSo every integer literal and any variable are all valid arguments. Any expression is forbidden.\nCaveat #3\nIf you use two every with the exact same argument, two variables with the exact same name will be created and it will rise a compile-time error.\nIf you can live with this limitations, every only needs the space of an uint32_t to work.\nL'articolo Eloquent non-blocking code: the Every construct proviene da Eloquent Arduino Blog.", "date_published": "2019-12-05T19:42:45+01:00", "date_modified": "2019-12-16T22:59:36+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "eloquent", "Eloquent library" ] }, { "id": "https://eloquentarduino.github.io/?p=554", "url": "https://eloquentarduino.github.io/2019/12/how-to-install-the-eloquent-library/", "title": "How to install the Eloquent library", "content_html": "In this short tutorial I'll show you how you can install the Eloquent library to take advange of all the good things it provides to you.
\nIt really is super simple, since the Eloquent library is no different from any other library you already installed on your computer, but I'll repeat the steps for clarity.
\n\n
The whole library is hosted on Github, so head over to the repo and click Clone or download > Download ZIP.
\n\nOnce downloaded, you should extract the zip into your Arduino libraries folder. The path will vary based on your OS and installation, but I expect you to know where it is.
\nWhen downloaded from Github, your zip and your folder will be named EloquentArduino-master
: rename the folder to just EloquentArduino
, without the master suffix.
If you follwed the steps correctly, the library is ready to be used.
\nDid you find this tutorial useful? Was is it easy to follow or did I miss something? Let me know in the comments so I can keep improving the blog.
\nL'articolo How to install the Eloquent library proviene da Eloquent Arduino Blog.
\n", "content_text": "In this short tutorial I'll show you how you can install the Eloquent library to take advange of all the good things it provides to you.\nIt really is super simple, since the Eloquent library is no different from any other library you already installed on your computer, but I'll repeat the steps for clarity.\n\n1. Download the zip from Github\nThe whole library is hosted on Github, so head over to the repo and click Clone or download > Download ZIP.\n\n2. Extract the zip to you library directory\nOnce downloaded, you should extract the zip into your Arduino libraries folder. The path will vary based on your OS and installation, but I expect you to know where it is.\n3. Strip the -master suffix\nWhen downloaded from Github, your zip and your folder will be named EloquentArduino-master: rename the folder to just EloquentArduino, without the master suffix.\n4. Done\nIf you follwed the steps correctly, the library is ready to be used.\nDid you find this tutorial useful? Was is it easy to follow or did I miss something? Let me know in the comments so I can keep improving the blog.\nL'articolo How to install the Eloquent library proviene da Eloquent Arduino Blog.", "date_published": "2019-12-05T17:18:48+01:00", "date_modified": "2020-01-25T17:15:38+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "Eloquent library" ] }, { "id": "https://eloquentarduino.github.io/?p=164", "url": "https://eloquentarduino.github.io/2019/11/how-to-write-clean-arduino-code/", "title": "How to write clean Arduino code: introducing the Eloquent library", "content_html": "Eloquent Arduino is an attempt to bring sanity and clarity in Arduino projects.\u00a0The purpose of this library is to create a wide range of constructs to clearly translate your ideas into meaningful code: stop writing spaghetti code only you can undestand, please! I'll show you how.
\n\n\n
Arduino sells itself as a platform well suited for beginners, and it is for sure; lots of non-tech people are able to bring their ideas to life thanks to this awesome platform.
\nNevertheless, I often stumble upon bits of code over the internet that make me question about the quality of the projects people are producing.
Even the Arduino official website is misleading in this sense, in my opinion, since it promotes a code style really straighforward, but suited for toy projects, with little logics and low complexity level.
\nHere's an example of what I'm talking about, copy-pasted from the Arduino official site (with comments removed):
\nconst int ledPin = LED_BUILTIN;\nint ledState = LOW;\nunsigned long previousMillis = 0; \nconst long interval = 1000; \n\nvoid setup() {\n pinMode(ledPin, OUTPUT);\n}\n\nvoid loop() {\n unsigned long currentMillis = millis();\n\n if (currentMillis - previousMillis >= interval) {\n previousMillis = currentMillis;\n\n if (ledState == LOW) {\n ledState = HIGH;\n } else {\n ledState = LOW;\n }\n\n digitalWrite(ledPin, ledState);\n }\n}
\nCan you tell what this code does with a minimum mental effort?
\nI don't think so (you may have recognized the async pattern and it actually blinks a LED in a non-blocking fashion).
THIS is the problem: most Arduino code is not clear at first glance, is not eloquent. By eloquent I mean code that speaks by itself, without the need for comments.
\nmost Arduino code is not clear at first glance, is not eloquent
Click To Tweet
What about the following?
\nDigitalOut led(LED_BUILTIN);\n\nvoid setup() {\n led.begin();\n}\n\nvoid loop() {\n every(1 Second) {\n led.toggle();\n }\n}
\nI swear this is valid code that compiles just fine. Hopefully, it does the exact same thing as above, yet it is far more readable and understandable.
\nCan you see my point now? Wouldn't it be much easier and reliable to code with the help of a set of such eloquent constructs / interfaces? I strongly believe it is, and this is why I'm writing this library.
\nAsynchronous programming, pin state managements, animations are bits of code that pop up over and over again in most of the projects, yet every time we start from zero and write the same boilerplate code over and over again.
Boilerplate code is not only tedious, but error-prone. And lengthy. Start writing eloquent code now!
Click To Tweet
Boilerplate code heavily relies on a fixed structure that could be hard to adapt to your specific case. Longer code means more chances to break something and more code to debug, which can waste lots of your valuable time.
\nI'm starting a series of posts where I'll document some of the classes and constructs the library provides to you. You can find the code on the Github repo.
\nL'articolo How to write clean Arduino code: introducing the Eloquent library proviene da Eloquent Arduino Blog.
\n", "content_text": "Eloquent Arduino is an attempt to bring sanity and clarity in Arduino projects.\u00a0The purpose of this library is to create a wide range of constructs to clearly translate your ideas into meaningful code: stop writing spaghetti code only you can undestand, please! I'll show you how.\n\n\nThe problem\nArduino sells itself as a platform well suited for beginners, and it is for sure; lots of non-tech people are able to bring their ideas to life thanks to this awesome platform.\nNevertheless, I often stumble upon bits of code over the internet that make me question about the quality of the projects people are producing. \nEven the Arduino official website is misleading in this sense, in my opinion, since it promotes a code style really straighforward, but suited for toy projects, with little logics and low complexity level.\nHere's an example of what I'm talking about, copy-pasted from the Arduino official site (with comments removed):\nconst int ledPin = LED_BUILTIN;\nint ledState = LOW;\nunsigned long previousMillis = 0; \nconst long interval = 1000; \n\nvoid setup() {\n pinMode(ledPin, OUTPUT);\n}\n\nvoid loop() {\n unsigned long currentMillis = millis();\n\n if (currentMillis - previousMillis >= interval) {\n previousMillis = currentMillis;\n\n if (ledState == LOW) {\n ledState = HIGH;\n } else {\n ledState = LOW;\n }\n\n digitalWrite(ledPin, ledState);\n }\n}\nCan you tell what this code does with a minimum mental effort?\nI don't think so (you may have recognized the async pattern and it actually blinks a LED in a non-blocking fashion).\nTHIS is the problem: most Arduino code is not clear at first glance, is not eloquent. By eloquent I mean code that speaks by itself, without the need for comments.\nmost Arduino code is not clear at first glance, is not eloquentClick To Tweet\nThe solution\nWhat about the following?\nDigitalOut led(LED_BUILTIN);\n\nvoid setup() {\n led.begin();\n}\n\nvoid loop() {\n every(1 Second) {\n led.toggle();\n }\n}\nI swear this is valid code that compiles just fine. Hopefully, it does the exact same thing as above, yet it is far more readable and understandable. \nCan you see my point now? Wouldn't it be much easier and reliable to code with the help of a set of such eloquent constructs / interfaces? I strongly believe it is, and this is why I'm writing this library.\nAsynchronous programming, pin state managements, animations are bits of code that pop up over and over again in most of the projects, yet every time we start from zero and write the same boilerplate code over and over again.\nBoilerplate code is not only tedious, but error-prone. And lengthy. Start writing eloquent code now!Click To Tweet\nBoilerplate code heavily relies on a fixed structure that could be hard to adapt to your specific case. Longer code means more chances to break something and more code to debug, which can waste lots of your valuable time.\n\nI'm starting a series of posts where I'll document some of the classes and constructs the library provides to you. You can find the code on the Github repo.\nL'articolo How to write clean Arduino code: introducing the Eloquent library proviene da Eloquent Arduino Blog.", "date_published": "2019-11-03T17:05:46+01:00", "date_modified": "2019-12-22T14:40:10+01:00", "authors": [ { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" } ], "author": { "name": "simone", "url": "https://eloquentarduino.github.io/author/simone/", "avatar": "http://1.gravatar.com/avatar/d670eb91ca3b1135f213ffad83cb8de4?s=512&d=mm&r=g" }, "tags": [ "eloquent", "Eloquent library" ] } ] }