planktoscope/scripts/planktoscope/imager.py

812 lines
31 KiB
Python
Raw Normal View History

Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
################################################################################
# Practical Libraries
################################################################################
# Logger library compatible with multiprocessing
from loguru import logger
# Library to get date and time for folder name and filename
import datetime
# Subprocess is used to update the gallery folder
import subprocess # nosec
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Library to be able to sleep for a given duration
import time
# Libraries manipulate json format, execute bash commands
import json, shutil
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Library for path and filesystem manipulations
import os
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Library for starting processes
import multiprocessing
# Basic planktoscope libraries
import planktoscope.mqtt
import planktoscope.light
# import planktoscope.streamer
import planktoscope.imager_state_machine
# import raspimjpeg module
import planktoscope.raspimjpeg
# Integrity verification module
import planktoscope.integrity
# Uuid module
import planktoscope.uuidName
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
################################################################################
# Streaming PiCamera over server
################################################################################
import socketserver
import http.server
import threading
import functools
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
################################################################################
# Classes for the PiCamera Streaming
################################################################################
class StreamingHandler(http.server.BaseHTTPRequestHandler):
# Webpage content containing the PiCamera Streaming
PAGE = """\
<html>
<head>
<title>PlanktonScope v2 | PiCamera Streaming</title>
</head>
<body>
<img src="stream.mjpg" width="100%" height="100%" />
</body>
</html>
"""
def __init__(self, delay, *args, **kwargs):
self.delay = delay
super(StreamingHandler, self).__init__(*args, **kwargs)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
@logger.catch
def do_GET(self):
if self.path == "/":
self.send_response(301)
self.send_header("Location", "/index.html")
self.end_headers()
elif self.path == "/index.html":
content = self.PAGE.encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.send_header("Content-Length", len(content))
self.end_headers()
self.wfile.write(content)
elif self.path == "/stream.mjpg":
self.send_response(200)
self.send_header("Age", 0)
self.send_header("Cache-Control", "no-cache, private")
self.send_header("Pragma", "no-cache")
self.send_header(
"Content-Type", "multipart/x-mixed-replace; boundary=FRAME"
)
self.end_headers()
try:
while True:
try:
with open("/dev/shm/mjpeg/cam.jpg", "rb") as jpeg:
frame = jpeg.read()
except FileNotFoundError as e:
logger.error(f"Camera has not been started yet")
time.sleep(5)
except Exception as e:
logger.exception(f"An exception occured {e}")
else:
self.wfile.write(b"--FRAME\r\n")
self.send_header("Content-Type", "image/jpeg")
self.send_header("Content-Length", len(frame))
self.end_headers()
self.wfile.write(frame)
self.wfile.write(b"\r\n")
time.sleep(self.delay)
2020-11-12 19:03:20 +01:00
except BrokenPipeError as e:
logger.info(f"Removed streaming client {self.client_address}")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
else:
self.send_error(404)
self.end_headers()
class StreamingServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
allow_reuse_address = True
daemon_threads = True
logger.info("planktoscope.imager is loaded")
################################################################################
# Main Imager class
################################################################################
class ImagerProcess(multiprocessing.Process):
"""This class contains the main definitions for the imager of the PlanktoScope"""
@logger.catch
2020-11-27 12:45:22 +01:00
def __init__(self, stop_event, iso=100, shutter_speed=1):
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
"""Initialize the Imager class
Args:
stop_event (multiprocessing.Event): shutdown event
iso (int, optional): ISO sensitivity. Defaults to 100.
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
shutter_speed (int, optional): Shutter speed of the camera. Defaults to 500.
"""
super(ImagerProcess, self).__init__(name="imager")
logger.info("planktoscope.imager is initialising")
if os.path.exists("/home/pi/PlanktonScope/hardware.json"):
# load hardware.json
with open("/home/pi/PlanktonScope/hardware.json", "r") as config_file:
configuration = json.load(config_file)
logger.debug(f"Hardware configuration loaded is {configuration}")
else:
logger.info(
"The hardware configuration file doesn't exists, using defaults"
)
configuration = {}
self.__camera_type = "v2.1"
# parse the config data. If the key is absent, we are using the default value
self.__camera_type = configuration.get("camera_type", self.__camera_type)
self.stop_event = stop_event
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__imager = planktoscope.imager_state_machine.Imager()
self.__img_goal = 0
self.__img_done = 0
self.__sleep_before = None
self.__pump_volume = None
2020-11-25 16:58:32 +01:00
self.__pump_direction = "FORWARD"
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__img_goal = None
self.imager_client = None
# Initialise the camera and the process
# Also starts the streaming to the temporary file
self.__camera = planktoscope.raspimjpeg.raspimjpeg()
try:
self.__camera.start()
except Exception as e:
logger.exception(
f"An exception has occured when starting up raspimjpeg: {e}"
)
exit(1)
if self.__camera.sensor_name == "IMX219": # Camera v2.1
self.__resolution = (3280, 2464)
elif self.__camera.sensor_name == "IMX477": # Camera HQ
self.__resolution = (4056, 3040)
else:
self.__resolution = (1280, 1024)
logger.error(
f"The connected camera {self.__camera.sensor_name} is not recognized, please check your camera"
)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__iso = iso
self.__shutter_speed = shutter_speed
self.__exposure_mode = "fixedfps"
2020-11-24 17:25:57 +01:00
self.__white_balance = "off"
self.__white_balance_gain = (
200,
140,
) # Those values were tested on a HQ camera to give a whitish background
self.__base_path = "/home/pi/data/img"
# Let's make sure the base path exists
if not os.path.exists(self.__base_path):
os.makedirs(self.__base_path)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__export_path = ""
self.__global_metadata = None
logger.info("Initialising the camera with the default settings")
try:
self.__camera.resolution = self.__resolution
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the resolution, trying again"
)
self.__camera.resolution = self.__resolution
time.sleep(0.1)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
try:
self.__camera.iso = self.__iso
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the ISO number, trying again"
)
self.__camera.iso = self.__iso
time.sleep(0.1)
try:
self.__camera.shutter_speed = self.__shutter_speed
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the shutter speed, trying again"
)
self.__camera.shutter_speed = self.__shutter_speed
time.sleep(0.1)
try:
self.__camera.exposure_mode = self.__exposure_mode
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the exposure mode, trying again"
)
self.__camera.exposure_mode = self.__exposure_mode
2020-11-24 17:25:57 +01:00
time.sleep(0.1)
try:
self.__camera.white_balance = self.__white_balance
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the white balance mode, trying again"
)
self.__camera.white_balance = self.__white_balance
time.sleep(0.1)
try:
self.__camera.white_balance_gain = self.__white_balance_gain
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the white balance gain, trying again"
)
self.__camera.white_balance_gain = self.__white_balance_gain
logger.success("planktoscope.imager is initialised and ready to go!")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
def pump_callback(self, client, userdata, msg):
2020-11-16 17:33:36 +01:00
"""Callback for when we receive an MQTT message
Args:
client: Paho MQTT client information
userdata: userdata of the message
msg: actual message received
"""
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Print the topic and the message
logger.info(f"{self.name}: {msg.topic} {str(msg.qos)} {str(msg.payload)}")
if msg.topic != "status/pump":
logger.error(
f"The received message has the wrong topic {msg.topic}, payload was {str(msg.payload)}"
)
return
payload = json.loads(msg.payload.decode())
logger.debug(f"parsed payload is {payload}")
2020-11-16 17:33:36 +01:00
if self.__imager.state.name == "waiting":
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
if payload["status"] == "Done":
self.__imager.change(planktoscope.imager_state_machine.Capture)
self.imager_client.client.message_callback_remove("status/pump")
self.imager_client.client.unsubscribe("status/pump")
else:
logger.info(f"the pump is not done yet {payload}")
else:
logger.error(
"There is an error, status is not waiting for the pump and yet we received a pump message"
)
2020-11-16 17:33:36 +01:00
def __message_image(self, last_message):
"""Actions for when we receive a message"""
if (
"sleep" not in last_message
or "volume" not in last_message
or "nb_frame" not in last_message
or "pump_direction" not in last_message
):
2020-11-16 17:33:36 +01:00
logger.error(f"The received message has the wrong argument {last_message}")
self.imager_client.client.publish("status/imager", '{"status":"Error"}')
return
# Change the state of the machine
self.__imager.change(planktoscope.imager_state_machine.Imaging)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Get duration to wait before an image from the different received arguments
self.__sleep_before = float(last_message["sleep"])
# Get volume in between two images from the different received arguments
self.__pump_volume = float(last_message["volume"])
2020-11-25 16:58:32 +01:00
# Get the pump direction message
self.__pump_direction = last_message["pump_direction"]
# Get the number of frames to image from the different received arguments
self.__img_goal = int(last_message["nb_frame"])
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Reset the counter to 0
self.__img_done = 0
self.imager_client.client.publish("status/imager", '{"status":"Started"}')
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
2020-11-16 17:33:36 +01:00
def __message_stop(self, last_message):
# Remove callback for "status/pump" and unsubscribe
self.imager_client.client.message_callback_remove("status/pump")
self.imager_client.client.unsubscribe("status/pump")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Stops the pump
self.imager_client.client.publish("actuator/pump", '{"action": "stop"}')
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
logger.info("The imaging has been interrupted.")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Publish the status "Interrupted" to via MQTT to Node-RED
2020-11-16 17:33:36 +01:00
self.imager_client.client.publish("status/imager", '{"status":"Interrupted"}')
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
planktoscope.light.interrupted()
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Change state to Stop
self.__imager.change(planktoscope.imager_state_machine.Stop)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
2020-11-16 17:33:36 +01:00
def __message_update(self, last_message):
if self.__imager.state.name == "stop":
if "config" not in last_message:
logger.error(
f"The received message has the wrong argument {last_message}"
)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.imager_client.client.publish(
"status/imager", '{"status":"Configuration message error"}'
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
)
return
logger.info("Updating the configuration now with the received data")
# Updating the configuration with the passed parameter in payload["config"]
self.__global_metadata = last_message["config"]
# Publish the status "Config updated" to via MQTT to Node-RED
self.imager_client.client.publish(
"status/imager", '{"status":"Config updated"}'
)
logger.info("Configuration has been updated")
else:
logger.error("We can't update the configuration while we are imaging.")
# Publish the status "Interrupted" to via MQTT to Node-RED
self.imager_client.client.publish("status/imager", '{"status":"Busy"}')
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
2020-11-16 17:33:36 +01:00
def __message_settings(self, last_message):
if self.__imager.state.name == "stop":
if "settings" not in last_message:
logger.error(
f"The received message has the wrong argument {last_message}"
)
self.imager_client.client.publish(
"status/imager", '{"status":"Camera settings error"}'
)
return
logger.info("Updating the camera settings now with the received data")
# Updating the configuration with the passed parameter in payload["config"]
settings = last_message["settings"]
if "resolution" in settings:
self.__resolution = settings.get("resolution", self.__resolution)
2020-11-16 17:33:36 +01:00
logger.debug(f"Updating the camera resolution to {self.__resolution}")
try:
self.__camera.resolution = self.__resolution
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the resolution, trying again"
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
)
self.__camera.resolution = self.__resolution
2020-11-16 17:33:36 +01:00
except ValueError as e:
logger.error("The requested resolution is not valid!")
self.imager_client.client.publish(
"status/imager", '{"status":"Error: Resolution not valid"}'
)
return
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
if "iso" in settings:
self.__iso = settings.get("iso", self.__iso)
logger.debug(f"Updating the camera iso to {self.__iso}")
2020-11-16 17:33:36 +01:00
try:
self.__camera.iso = self.__iso
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the ISO number, trying again"
)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__camera.iso = self.__iso
2020-11-16 17:33:36 +01:00
except ValueError as e:
logger.error("The requested ISO number is not valid!")
self.imager_client.client.publish(
"status/imager", '{"status":"Error: Iso number not valid"}'
)
return
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
if "shutter_speed" in settings:
self.__shutter_speed = settings.get(
"shutter_speed", self.__shutter_speed
)
logger.debug(
f"Updating the camera shutter speed to {self.__shutter_speed}"
)
2020-11-16 17:33:36 +01:00
try:
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__camera.shutter_speed = self.__shutter_speed
2020-11-16 17:33:36 +01:00
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the shutter speed, trying again"
)
self.__camera.shutter_speed = self.__shutter_speed
except ValueError as e:
logger.error("The requested shutter speed is not valid!")
self.imager_client.client.publish(
"status/imager", '{"status":"Error: Shutter speed not valid"}'
)
return
2020-11-27 12:45:22 +01:00
if "white_balance_gain" in settings:
if "red" in settings["white_balance_gain"]:
logger.debug(
2020-11-27 18:39:09 +01:00
f"Updating the camera white balance red gain to {settings['white_balance_gain']}"
2020-11-27 12:45:22 +01:00
)
self.__white_balance_gain = (
settings["white_balance_gain"].get(
"red", self.__white_balance_gain[0]
),
self.__white_balance_gain[1],
)
if "blue" in settings["white_balance_gain"]:
logger.debug(
2020-11-27 18:39:09 +01:00
f"Updating the camera white balance blue gain to {settings['white_balance_gain']}"
2020-11-27 12:45:22 +01:00
)
self.__white_balance_gain = (
self.__white_balance_gain[0],
settings["white_balance_gain"].get(
"blue", self.__white_balance_gain[1]
),
)
logger.debug(
2020-11-27 18:39:09 +01:00
f"Updating the camera white balance gain to {self.__white_balance_gain}"
2020-11-27 12:45:22 +01:00
)
try:
self.__camera.white_balance_gain = self.__white_balance_gain
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the white balance gain, trying again"
)
self.__camera.white_balance_gain = self.__white_balance_gain
except ValueError as e:
logger.error("The requested white balance gain is not valid!")
self.imager_client.client.publish(
"status/imager",
'{"status":"Error: White balance gain not valid"}',
)
return
2020-11-27 18:39:09 +01:00
if "white_balance" in settings:
logger.debug(
f"Updating the camera white balance mode to {settings['white_balance']}"
)
self.__white_balance = settings.get(
"white_balance", self.__white_balance
)
logger.debug(
f"Updating the camera white balance mode to {self.__white_balance}"
)
try:
self.__camera.white_balance = self.__white_balance
except TimeoutError as e:
logger.error(
"A timeout has occured when setting the white balance, trying again"
)
self.__camera.white_balance = self.__white_balance
except ValueError as e:
logger.error("The requested white balance is not valid!")
self.imager_client.client.publish(
"status/imager",
f'{"status":"Error: White balance mode {self.__white_balance} is not valid"}',
)
return
# Publish the status "Config updated" to via MQTT to Node-RED
self.imager_client.client.publish(
"status/imager", '{"status":"Camera settings updated"}'
)
logger.info("Camera settings have been updated")
else:
2020-11-16 17:33:36 +01:00
logger.error("We can't update the camera settings while we are imaging.")
# Publish the status "Interrupted" to via MQTT to Node-RED
self.imager_client.client.publish("status/imager", '{"status":"Busy"}')
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
2020-11-16 17:33:36 +01:00
@logger.catch
def treat_message(self):
action = ""
if self.imager_client.new_message_received():
logger.info("We received a new message")
last_message = self.imager_client.msg["payload"]
logger.debug(last_message)
action = self.imager_client.msg["payload"]["action"]
logger.debug(action)
self.imager_client.read_message()
# If the command is "image"
if action == "image":
# {"action":"image","sleep":5,"volume":1,"nb_frame":200}
self.__message_image(last_message)
elif action == "stop":
self.__message_stop(last_message)
elif action == "update_config":
self.__message_update(last_message)
elif action == "settings":
self.__message_settings(last_message)
elif action not in ["image", "stop", "update_config", "settings", ""]:
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
logger.warning(
f"We did not understand the received request {action} - {last_message}"
)
2020-11-25 16:58:32 +01:00
def __pump_message(self):
"""Sends a message to the pump process"""
planktoscope.light.pumping()
2020-11-25 16:58:32 +01:00
# Pump during a given volume
self.imager_client.client.publish(
"actuator/pump",
json.dumps(
{
"action": "move",
"direction": self.__pump_direction,
"volume": self.__pump_volume,
"flowrate": 2,
}
),
)
2020-11-16 17:33:36 +01:00
def __state_imaging(self):
# subscribe to status/pump
self.imager_client.client.subscribe("status/pump")
self.imager_client.client.message_callback_add(
"status/pump", self.pump_callback
)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Definition of the few important metadata
local_metadata = {
"acq_local_datetime": datetime.datetime.now().isoformat().split(".")[0],
"acq_camera_resolution": self.__resolution,
"acq_camera_iso": self.__iso,
"acq_camera_shutter_speed": self.__shutter_speed,
"acq_uuid": planktoscope.uuidName.uuidMachineName(
machine=planktoscope.uuidName.getSerial()
),
"sample_uuid": planktoscope.uuidName.uuidMachineName(
machine=planktoscope.uuidName.getSerial()
),
}
# Concat the local metadata and the metadata from Node-RED
self.__global_metadata = {**self.__global_metadata, **local_metadata}
2020-12-03 16:45:01 +01:00
if "object_date" not in self.__global_metadata:
# If this path exists, then ids are reused when they should not
logger.error(f"The metadata did not contain object_date!")
self.imager_client.client.publish(
"status/imager",
'{"status":"Configuration update error: object_date is missing!"}',
)
# Reset the counter to 0
self.__img_done = 0
# Change state towards stop
self.__imager.change(planktoscope.imager_state_machine.Stop)
planktoscope.light.error()
return
logger.info("Setting up the directory structure for storing the pictures")
self.__export_path = os.path.join(
self.__base_path,
self.__global_metadata["object_date"],
str(self.__global_metadata["sample_id"]),
str(self.__global_metadata["acq_id"]),
)
if os.path.exists(self.__export_path):
# If this path exists, then ids are reused when they should not
logger.error(f"The export path at {self.__export_path} already exists")
self.imager_client.client.publish(
"status/imager",
'{"status":"Configuration update error: Chosen id are already in use!"}',
)
# Reset the counter to 0
self.__img_done = 0
# Change state towards stop
self.__imager.change(planktoscope.imager_state_machine.Stop)
planktoscope.light.error()
return
else:
# create the path!
os.makedirs(self.__export_path)
# Export the metadata to a json file
logger.info("Exporting the metadata to a metadata.json")
metadata_filepath = os.path.join(self.__export_path, "metadata.json")
with open(metadata_filepath, "w") as metadata_file:
json.dump(self.__global_metadata, metadata_file)
logger.debug(
f"Metadata dumped in {metadata_file} are {self.__global_metadata}"
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
)
# Create the integrity file in this export path
try:
planktoscope.integrity.create_integrity_file(self.__export_path)
except FileExistsError as e:
logger.info(
f"The integrity file already exists in this export path {self.__export_path}"
)
# Add the metadata.json file to the integrity file
try:
planktoscope.integrity.append_to_integrity_file(metadata_filepath)
except FileNotFoundError as e:
logger.error(
f"{metadata_filepath} was not found, the metadata.json may not have been created properly!"
)
2020-11-25 16:58:32 +01:00
self.__pump_message()
# Change state towards Waiting for pump
self.__imager.change(planktoscope.imager_state_machine.Waiting)
def __state_capture(self):
planktoscope.light.imaging()
filename = f"{datetime.datetime.now().strftime('%H_%M_%S_%f')}.jpg"
# Define the filename of the image
filename_path = os.path.join(self.__export_path, filename)
logger.info(
f"Capturing image {self.__img_done + 1}/{self.__img_goal} to {filename_path}"
)
2020-11-29 14:28:31 +01:00
# Sleep a duration before to start acquisition
time.sleep(self.__sleep_before)
# Capture an image with the proper filename
try:
self.__camera.capture(filename_path)
except TimeoutError as e:
logger.error("A timeout happened while waiting for a capture to happen")
# Publish the name of the image to via MQTT to Node-RED
self.imager_client.client.publish(
"status/imager",
f'{{"status":"Image {self.__img_done + 1}/{self.__img_goal} WAS NOT CAPTURED! STOPPING THE PROCESS!"}}',
)
# Reset the counter to 0
self.__img_done = 0
2020-12-03 16:29:12 +01:00
self.__img_goal = 0
# Change state towards stop
self.__imager.change(planktoscope.imager_state_machine.Stop)
planktoscope.light.error()
return
# Add the checksum of the captured image to the integrity file
try:
planktoscope.integrity.append_to_integrity_file(filename_path)
except FileNotFoundError as e:
logger.error(
f"{filename_path} was not found, the camera may not have worked properly!"
)
# Publish the name of the image to via MQTT to Node-RED
self.imager_client.client.publish(
"status/imager",
f'{{"status":"Image {self.__img_done + 1}/{self.__img_goal} has been imaged to {filename}"}}',
)
# Update the gallery with the new image
subprocess.Popen(
"thumbsup --config /home/pi/PlanktonScope/scripts/thumbsup/config.json".split()
) # nosec
# Increment the counter
self.__img_done += 1
# If counter reach the number of frame, break
if self.__img_done >= self.__img_goal:
# Reset the counter to 0
self.__img_done = 0
# Publish the status "Done" to via MQTT to Node-RED
self.imager_client.client.publish("status/imager", '{"status":"Done"}')
# Change state towards done
self.__imager.change(planktoscope.imager_state_machine.Stop)
planktoscope.light.ready()
return
else:
# We have not reached the final stage, let's keep imaging
# subscribe to status/pump
self.imager_client.client.subscribe("status/pump")
self.imager_client.client.message_callback_add(
"status/pump", self.pump_callback
)
2020-11-25 16:58:32 +01:00
self.__pump_message()
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# Change state towards Waiting for pump
self.__imager.change(planktoscope.imager_state_machine.Waiting)
2020-11-16 17:33:36 +01:00
@logger.catch
def state_machine(self):
if self.__imager.state.name == "imaging":
self.__state_imaging()
return
elif self.__imager.state.name == "capture":
self.__state_capture()
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
return
2020-11-16 17:33:36 +01:00
elif self.__imager.state.name == ["waiting", "stop"]:
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
return
################################################################################
# While loop for capturing commands from Node-RED
################################################################################
@logger.catch
def run(self):
"""This is the function that needs to be started to create a thread"""
logger.info(
f"The imager control thread has been started in process {os.getpid()}"
)
# MQTT Service connection
self.imager_client = planktoscope.mqtt.MQTT_Client(
topic="imager/#", name="imager_client"
)
2020-10-06 11:40:25 +02:00
self.imager_client.client.publish("status/imager", '{"status":"Starting up"}')
2020-11-27 18:57:43 +01:00
if self.__camera.sensor_name == "IMX219": # Camera v2.1
self.imager_client.client.publish(
"status/imager", '{"camera_name":"Camera v2.1"}'
)
elif self.__camera.sensor_name == "IMX477": # Camera HQ
self.imager_client.client.publish(
"status/imager", '{"camera_name":"HQ Camera"}'
)
else:
self.imager_client.client.publish(
"status/imager", '{"camera_name":"Not recognized"}'
)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
logger.info("Starting the streaming server thread")
address = ("", 8000)
fps = 16
refresh_delay = 1 / fps
handler = functools.partial(StreamingHandler, refresh_delay)
server = StreamingServer(address, handler)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.streaming_thread = threading.Thread(
target=server.serve_forever, daemon=True
)
self.streaming_thread.start()
# Publish the status "Ready" to via MQTT to Node-RED
self.imager_client.client.publish("status/imager", '{"status":"Ready"}')
2020-10-06 11:40:25 +02:00
logger.success("Camera is READY!")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
# This is the main loop
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
while not self.stop_event.is_set():
self.treat_message()
self.state_machine()
time.sleep(0.0001)
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
logger.info("Shutting down the imager process")
self.imager_client.client.publish("status/imager", '{"status":"Dead"}')
logger.debug("Stopping the raspimjpeg process")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.__camera.close()
logger.debug("Stopping the streaming thread")
server.shutdown()
2020-10-06 11:40:25 +02:00
logger.debug("Stopping MQTT")
Extraction and refactor of the python code from node-red flow The rationale for this rewrite is to improve the readability, the modularity, the reliability and the future-proofing of the main python script. All in all, this is now 124 commits that are going to be squashed and merged together, spanning more than two weeks of development and testing. Please test away this release and break things. An upgrading guide will be published in the coming days, along with a new image for people to use if they don't want to upgrade on their own. Read along if you want to know all the goodies! As a starter, the python script was extracted from the main flow, and now lives in its own files at `PlantonScope/scripts/*`. We set up the auto formatting of the code by using [Black](https://github.com/psf/black). This make the code clearer and uniform. We are using the default settings, so if you just install Black and set your editor to format on save using it, you should be good to go. The code is separated in four main processes, each with a specific set of responsibilities: - The main process controls all the others, starts everything up and cleans up on shutdown - The stepper process manages the stepper movements. It's now possible to have simultaneous movements of both motors (this closes #38 ). - The imager process controls the camera and the streaming server via a state machine. - The segmenter process manages the segmentation and its outputs. The segmentation happens recursively in all folders in `/home/pi/PlanktonScope/img/`. Each folder has its own output archive, and bug #26 is now closed. Those processes communicates together using MQTT and json messages. Each message is adressed to one topic. The high level topic controls which process receives the message. The details of each topic is at the end of this commit message. Every imaging sessions has now its own folder, under the `img` root. Metadata are saved individually for every session, in a JSON file in the same directory as the pictures. The configuration is not parsed from `config.json` anymore and passed directly through MQTT messages to the concerned process. A new configuration file has been created: `hardware.json`. This file contains information related to your specific hardware configuration. You can choose to reverse the connection of the motors for example, but you can also define specific speed limits and steps number for your pump and focus stage. This will make it easier for people who wants to experiment with different kind of hardware. It's not necessary to have this file though. If it doesn't exists, the default configuration will be applied. The code is architectured around 6 modules and about 10 classes. I encourage you to have a look at the files, they're pretty straightforward to understand. There is a lot of work left around the node-red code refactoring, dashboard ui improvements, better and clearer LED messages, OLED screen integration and finer control of the segmentation process, but this is quite good for now. Here is the topic lists for MQTT and the corresponding messages. - actuator : This topic adresses the stepper control thread No publication under this topic should happen from the python process - actuator/pump : Control of the pump The message is a json object {"action":"move", "direction":"FORWARD", "volume":10, "flowrate":1} to move 10mL forward at 1mL/min action can be "move" or "stop" Receive only - actuator/focus : Control of the focus stage The message is a json object, speed is optional {"action":"move", "direction":"UP", "distance":0.26, "speed":1} to move up 10mm action can be "move" or "stop" Receive only - imager/image : This topic adresses the imaging thread Is a json object with {"action":"image","sleep":5,"volume":1,"nb_frame":200} sleep in seconds, volume in mL Can also receive a config update message: {"action":"config","config":[...]} Can also receive a camera settings message: {"action":"settings","iso":100,"shutter_speed":40} Receive only - segmenter/segment : This topic adresses the segmenter process Is a json object with {"action":"segment"} Receive only - status : This topics sends feedback to Node-Red No publication or receive at this level - status/pump : State of the pump Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/focus : State of the focus stage Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Done, Interrupted Publish only - status/imager : State of the imager Is a json object with {"status":"Start", "time_left":25} Status is one of Started, Ready, Completed or 12_11_15_0.1.jpg has been imaged. Publish only - status/segmenter : Status of the segmentation - status/segmenter/name - status/segmenter/object_id - status/segmenter/metric Here is the original commit history: * Extract python main.py from flow * Fix bug in server addresses These addresses should be the loopback device instead of the network address of the device. Using the loopback address will not necessitate to update the script when the network address changes. * clean up picamera import * changes to main python and flow: update MQTT requests address to localhost (bugfix) update streaming output address to nothing update main flow to remove python script references and location * Automatically initialise imaging led on startup to off state. * Add the ability to invert outputs of the motor We added a key to config.json "hardware_config" with a subkey "stepper_reverse". If this key is present in the config file and set to 1, the output of the motors are inversed (stepper2 becomes the pump motor and stepper1 the focus motor) * move all non main script to a subfolder * add __init__.py to package * light module rewrite * json cleanup and absolute path for config file * light.py forgot to import subprocess #oups * Add command to turn the leds off * Auto formatting of main.py I've used Black with default settings, see https://github.com/psf/black * First commit of stepper.py Pump parameters still needs to be checked and tuned. * addition of hardware details in config.json * Introduce hardware.json to replace the `hardware_config` of config.json * stepper.py: calibration, typos * creates the MQTT_Client class * pump_max_speed is now in ml/min to help readability * forgot to add self to the class def * addition of threading capabilities to stepper.py (UNTESTED) * mqtt: fix topic bug * remove counter * mqtt add doc about topics * stepper.py creates an "actuator/*/state" topic * stepper.py: rename mqtt_client to pump_client * mqtt.py: add details about topics * stepper.py: rename pump_client to actuator_client * topic was not split properly and a part was lost * switch to f-strings for mqtt.py * cosmetic update * stepper.py: folder name will be planktoscope change calls * hardware.json became more straightforward * stepper.py syntax bugs * stepper.py addition of a received stop command * stepper.py: update to max travel distance * stepper.py: several typos here * rename folder * main.py: reword to reflect folder rename * main.py: remove logic that has been moved to stepper.py and mqtt.py * main.py: update to add mqtt imaging client * mqtt.py: make command and args local to class and output more verbose * make stepper.py a class * main.py: instantiate stepper class and call it * main.py: name mqtt client * update to main.json to reflect main.py changes * fix bugs around pump control * update flows to latest version from Thibault * distance can be a small value, and definitevely should be a float. * unify mqtt topics * unify mqtt output in the main flow * first logger implementation, uses loguru * mqtt: add reason to on_connect * mqtt: add on_disconnect handler * stepper: add more logger calls for debug mainly * main: add levels for logger * imager.py: first move of the imager logic * imager: time import cleanup * imager: morphocut import cleanup * imager: skimage import cleanup * imager: finishing import cleanup * imager: Class creation - WIP Also provides a fix for #26 (see line 190). * imager: threading is needed for Condition() * streamer: get the streamer server its own file * imager: creates start_camera and get the server creation out * imager: subclass multiprocessing.Process * imager: get Pipeline creation its own function * imager: cleanup of self calls * main: code removal and corresponding calls to newly created classes * imager: various formatting changes * main: management of signal shutdown * add requirements.txt * mqtt: messages are now json objects Also, addition of a flag on receiving a new message * mqtt: make message private and add logic to synchronise * stepper: creates the stepper class * stepper: use the new class * stepper: uses the new logic * stepper: add the shutdown event * stepper: add shutdown method * main: add shutdown event * imager: graceful shutdown * stepper: nicer way of checking the Eevnt * self is a required first argument for a method in a class Especially if you use said class private members! * python: various typos and small errors in import * stepper: create mqtt client during init * stepper: instanciate the mqtt client inside run Otherwise it's not accessible from inside the loop. It's a PITA, more information at https://stackoverflow.com/questions/17172878/using-pythons-multiprocessing-process-class * stepper: little bugs and typos all around * mqtt: add shutdown method * mqtt: add connect in init * stepper: fix bugs, sanitize inputs * stepper: work on delay prediction improvements * stepper: json is mean, double quote are mandatory inside * mqtt: add details about message exchanged * imager: first implementation of json messages * main.json: add new tab for RPi management + json for payloads * imager: add state_machine class * stepper: publish last will * imager: major refactor * main: make streaming server process a daemon * mqtt: insert debug statement on close * main: reorder imports * imager: make it work! Reinsert the streaming server logic in there, because there is a problem with the synchronisation part otherwise. Also, eventually, StreamingOuput() will have to be made not global Final very critical learning: it's super duper important to make sure the memory split is at least 256Meg for the GPU. Chaos ensues otherwise * main: changes to accomodate the streamer/imager fusino * imager_state_machine: insert states transition description * stepper: cleanup of code * segmenter: creation of the class * python: include segmenter changes * remove unused files * stepper: check existence of hardware.json * main.json: changes to reflect the python script evolution * remove unecessary TODOs and add some others * main: add check for config and directories * imager: update_config is implemented and we have better management of directories now * segmenter: now work recursively in all folders * flow: the configuration is now sent via mqtt * segmenter: better manage pipeline error * segmenter: declaration of archive_fn in init * imager: small bugs and typos * main: add uniqueID output * imager: add the camera settings message We can now update the ISO, shutter speed and resolution from Node-Red * package.json: update dependencies
2020-09-28 11:05:27 +02:00
self.imager_client.shutdown()
# self.streaming_thread.kill()
2020-10-06 11:40:25 +02:00
logger.success("Imager process shut down! See you!")
2020-10-06 11:42:07 +02:00
# This is called if this script is launched directly
if __name__ == "__main__":
# TODO This should be a test suite for this library
pass