amc:ss2024:irrigantion_cart_nozzle:start
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
amc:ss2024:irrigantion_cart_nozzle:start [2024/07/31 00:58] – [Conclusion] amr.abdelkhalek | amc:ss2024:irrigantion_cart_nozzle:start [2024/10/20 23:40] (current) – [Enhancing the If-Condition for Better Plant Recognition] amr.abdelkhalek | ||
---|---|---|---|
Line 36: | Line 36: | ||
The following diagram Figure 1 shows the overall layout of our project: | The following diagram Figure 1 shows the overall layout of our project: | ||
+ | the system uses LIDAR sensors for distance measurements, | ||
+ | * **VLX53L0X (LIDAR Sensors):** | ||
+ | Horizontal Distance Input: One VLX53L0X sensor measures horizontal distance. | ||
+ | Vertical Distance Input: Another VLX53L0X sensor measures vertical distance. | ||
+ | * **ESP32-S3-WROOM-1 (Arduino): | ||
+ | Receives distance readings from both VLX53L0X sensors (horizontal and vertical distance). | ||
+ | Processes these readings and performs various tasks based on the data. | ||
+ | * **LED Light/ | ||
+ | Connected to the Arduino. | ||
+ | Can be turned on or off based on commands from the Arduino. | ||
+ | * **Battery/ | ||
+ | Powers the ESP32-S3-WROOM-1. | ||
+ | * **MQTT Server:** | ||
+ | Receives processed readings (distance data and actuator state) from the Arduino. | ||
+ | Sends actuator control commands (like " | ||
+ | * **Personal Computer with Jupyter Notebooks: | ||
+ | Communicates with the MQTT server to receive the distance readings and actuator state. | ||
+ | control commands to the MQTT server, which then relays them to the Arduino. | ||
- | {{amc: | + | < |
- | **Figure 1: Project Layout** | + | |
The following Figure 2 is the implementation of the previous layout in real-life application: | The following Figure 2 is the implementation of the previous layout in real-life application: | ||
+ | < | ||
- | |||
- | {{amc: | ||
- | **Figure 2: Real-life Implementation** | ||
- **Vertical VL53L0X Sensor** | - **Vertical VL53L0X Sensor** | ||
Line 284: | Line 299: | ||
===== Python Code ===== | ===== Python Code ===== | ||
- | For installing the necessary libraries, you can download the following text file " | + | ==== Required Libraries ==== |
- | <file txt requirements.txt> | + | To install the required libraries for the project, open and download the following text file "requirements.txt" |
+ | <file txt requirements.txt> | ||
bqplot | bqplot | ||
traits | traits | ||
Line 294: | Line 310: | ||
ipywidgets | ipywidgets | ||
pandas | pandas | ||
- | |||
</ | </ | ||
- | and run the python code | + | Then run the following terminal command in the environment where you will run the project: |
<code python> | <code python> | ||
pip install -r requirements.txt | pip install -r requirements.txt | ||
- | </ | + | </ |
==== MQTT Client Setup and Configuration ==== | ==== MQTT Client Setup and Configuration ==== | ||
Line 526: | Line 542: | ||
==== Defining and Initializing System States with Enum ==== | ==== Defining and Initializing System States with Enum ==== | ||
- | <code python> | + | |
class State(Enum): | class State(Enum): | ||
IDLE = 1 # State when the system is idle | IDLE = 1 # State when the system is idle | ||
Line 1101: | Line 1117: | ||
10001.0 | 10001.0 | ||
10002.0 | 10002.0 | ||
- | ==== Enhancing the If-Condition for Better Plant Recognition ==== | ||
- | To enhance the condition for recognizing plants more accurately, we need to implement peak detection logic and replace the older one; to ensure only true plants are detected. This approach reduces the likelihood of false positives caused by objects with heights above 120 mm even as mentioned earlier and help creating an automated system that keeps track of the plants. | ||
- | |||
==== Enhancing the If-Condition for Better Plant Recognition ==== | ==== Enhancing the If-Condition for Better Plant Recognition ==== | ||
- | To enhance the condition for recognizing plants more accurately, we need to implement peak detection logic and replace the older one; to ensure only true plants are detected. This approach reduces the likelihood of false positives caused by objects with heights above 120 mm even as mentioned earlier and help creating | + | To enhance the condition for recognizing plants more accurately, we need to implement peak detection logic and replace the older one; to ensure only true plants are detected. This approach reduces the likelihood of false positives caused by objects with heights above 120 mm even as mentioned earlier and helps create |
- | In order to implement this, testing the time required to detect | + | In order to implement this, testing the time required to detect plants' |
This was tested on our array of 870 elements detecting the two peaks by the following line of command in the peak detecting step: | This was tested on our array of 870 elements detecting the two peaks by the following line of command in the peak detecting step: | ||
<code python> | <code python> | ||
- | %%time #outputs the processing time | + | # Measure the time taken to find peaks in the array |
+ | %%time | ||
+ | |||
+ | # Find peaks in the array ' | ||
peaks5, wid_dis = find_peaks(array_z, | peaks5, wid_dis = find_peaks(array_z, | ||
</ | </ | ||
Line 1120: | Line 1136: | ||
Wall time: 0 ns | Wall time: 0 ns | ||
+ | # Note: The processing time changes if we have to plot every time, which in our application, | ||
- | this of course changes if we have to plot everytime which of course in our application we used the faster bqplot modules but regardless: | ||
<code python> | <code python> | ||
+ | # Measure the time taken to find peaks in the array | ||
%%time #outputs the processing time | %%time #outputs the processing time | ||
+ | |||
+ | # Find peaks in the array ' | ||
peaks5, wid_dis = find_peaks(array_z, | peaks5, wid_dis = find_peaks(array_z, | ||
- | plt.plot(peaks5, | + | |
+ | # Plot the original data with the detected peaks | ||
+ | plt.plot(peaks5, | ||
+ | plt.plot(array_z) | ||
+ | plt.legend([' | ||
</ | </ | ||
Line 1135: | Line 1159: | ||
<code python> | <code python> | ||
+ | # Measure the time taken to plot the results | ||
%%time #outputs the processing time | %%time #outputs the processing time | ||
- | plt.plot(peaks5, | + | |
+ | # Plot the original data with the detected peaks | ||
+ | plt.plot(peaks5, | ||
+ | plt.plot(array_z); | ||
+ | plt.legend([' | ||
</ | </ | ||
| | ||
Line 1142: | Line 1171: | ||
Wall time: 54.4 ms | Wall time: 54.4 ms | ||
| | ||
- | confirming | + | Confirming |
Line 1148: | Line 1177: | ||
<code python> | <code python> | ||
- | N1 = 870 | + | # Initialize the arrays and variables for testing with our older real data |
- | z_data = np.array(np.zeros(N1)) | + | |
- | peaks_total_xposition = np.array([]) | + | N1 = 870 # Number of elements in the array |
- | peaks_last = np.array([]) # Initialize with empty arrays | + | z_data = np.array(np.zeros(N1)) |
- | counter = 0 | + | peaks_total_xposition = np.array([]) |
- | counter_2 = 0 | + | peaks_last = np.array([]) |
- | checker = N1/10 #is set to check 10 times ever 1 time the z_data array is completely filled | + | counter = 0 # Counter to keep track of the number of readings |
+ | counter_2 = 0 # Secondary counter to keep track of the number of readings | ||
+ | checker = N1 / 10 | ||
</ | </ | ||
| | ||
- | and now to check the output and the time of using this in a for-loop that activates for every reading to again model our on_message function | + | # Now check the output and the time of using this in a for-loop that activates for every reading to model our on_message function |
<code python> | <code python> | ||
- | %%time | + | |
+ | %%time | ||
+ | # Iterate through each element in array_z | ||
for i in array_z: | for i in array_z: | ||
- | z_data = np.roll(z_data, | + | |
- | counter += 1 | + | |
- | counter_2 += 1 | + | counter += 1 # Increment the counter |
+ | counter_2 += 1 # Increment the counter | ||
if counter == checker: | if counter == checker: | ||
- | peaks_wd, wid_dis = find_peaks(z_data, | + | |
- | if | + | |
- | peaks_total_xposition = np.sort(np.unique(np.append(peaks_total_xposition, | + | if |
- | peaks_last = peaks_wd | + | # If the number of detected peaks is greater than the last detected peaks which indicates a new peak ... |
- | counter = 0 | + | # Update the total x positions of the peaks |
+ | # np.append(peaks_total_xposition, | ||
+ | # np.unique(...): | ||
+ | # np.sort(...): | ||
+ | peaks_total_xposition = np.sort(np.unique(np.append(peaks_total_xposition, | ||
+ | peaks_last = peaks_wd | ||
+ | counter = 0 # Reset the counter | ||
if counter_2 == N1: | if counter_2 == N1: | ||
- | z_data = np.array(np.zeros(N1)) | + | |
+ | |||
+ | |||
</ | </ | ||
Line 1178: | Line 1221: | ||
Wall time: 35.8 ms | Wall time: 35.8 ms | ||
- | It may be a bit of unnecessary to do the sorting unique check every time/ | + | It may be a bit unnecessary to do the sorting unique check every time/ |
and the output was the same: | and the output was the same: | ||
<code python> | <code python> | ||
+ | # Print the total x positions of the peaks | ||
peaks_total_xposition | peaks_total_xposition | ||
</ | </ | ||
- | array([253., | + | array([253., |
| | ||
Feel encouraged to compare with our last trial on the full array of array_z... it produces the same output | Feel encouraged to compare with our last trial on the full array of array_z... it produces the same output | ||
Line 1204: | Line 1248: | ||
peaks_wd, wid_dis = find_peaks(z_data, | peaks_wd, wid_dis = find_peaks(z_data, | ||
if | if | ||
- | peak_positions = np.add(np.full(len(array_x[peaks_wd]), | + | |
+ | # np.full(len(array_x[peaks_wd]), | ||
+ | # where every element is equal to arm_sens_lead (300 mm). This represents the lead distance for the sensor. | ||
+ | # array_x[peaks_wd]: | ||
+ | # np.add(...): | ||
+ | | ||
peaks_total_xposition = np.sort(np.unique(np.append(peaks_total_xposition, | peaks_total_xposition = np.sort(np.unique(np.append(peaks_total_xposition, | ||
peaks_last = peaks_wd | peaks_last = peaks_wd | ||
Line 1213: | Line 1262: | ||
<code python> | <code python> | ||
- | peaks_total_xposition | + | peaks_total_xposition |
</ | </ | ||
array([553., | array([553., | ||
| | ||
- | assuming | + | Assuming |
==== Enhancing the If-Condition for Better Plant Recognition - Implementation ==== | ==== Enhancing the If-Condition for Better Plant Recognition - Implementation ==== | ||
- | We move to our on_message function and apply the new findings: | + | Now we will move to our on_message function and apply the new findings: |
Line 1249: | Line 1299: | ||
| | ||
s = f" | s = f" | ||
+ | # Check if the system is idle and the current x position is at a peak position | ||
if (state == state.IDLE) & np.isin(x, | if (state == state.IDLE) & np.isin(x, | ||
client.publish(" | client.publish(" | ||
state = state.WATERING | state = state.WATERING | ||
+ | # Check if the system is watering and the current x position is not at a peak position | ||
if (state == state.WATERING) & np.isin(x, | if (state == state.WATERING) & np.isin(x, | ||
client.publish(" | client.publish(" | ||
state = state.IDLE | state = state.IDLE | ||
- | #check if the water is off and the cart position is on a plant location .. turns it on | + | |
- | #check if the water is on and the cart position is not on a plant location (inverts the logic).. turns it off | + | #checks |
+ | #checks | ||
| | ||
Line 1298: | Line 1350: | ||
plotter.update_data2(data2) | plotter.update_data2(data2) | ||
| | ||
- | # out.append_stdout(s + " | + | # out.append_stdout(s + " |
+ | | ||
</ | </ | ||
====== VI. Conclusion ====== | ====== VI. Conclusion ====== | ||
- | Further development | + | This project addresses water scarcity by developing an automated irrigation cart that conserves water through precise plant detection |
+ | |||
+ | Utilizing VL53L0X sensors and an Arduino, | ||
+ | |||
+ | The integration of MQTT for communication and Python for data processing lays the groundwork for future enhancements, | ||
+ | |||
+ | Future enhancements will focus on refining | ||
Sensors may be replaced in the future with faster detecting ones so that their algorithms may be easier or more straight forward to accommodate a much larger number of sensors. | Sensors may be replaced in the future with faster detecting ones so that their algorithms may be easier or more straight forward to accommodate a much larger number of sensors. | ||
Line 1308: | Line 1368: | ||
Multiplexers most probably will be used for connecting with the multiple number of nozzles for our system e.g. irrigating 30 rows at the same time. Each of which will have at least a single sensor, and a water nozzle. 30 controlling MOSFETS hence may be connected to our microcontroller plus the 30 sensors. | Multiplexers most probably will be used for connecting with the multiple number of nozzles for our system e.g. irrigating 30 rows at the same time. Each of which will have at least a single sensor, and a water nozzle. 30 controlling MOSFETS hence may be connected to our microcontroller plus the 30 sensors. | ||
- | Further studies are going to be done on the rush in current in case large nozzles will be used .. and 30 of those will mean multiple of that rush in current, | + | Further studies are going to be done on the rush in current in case large nozzles will be used .. and 30 of those will mean multiple of that rush in current. Additionally, this further research will be conducted on managing current surges when using large nozzles might introduce the possibility of implementing PWM to ensure |
https:// | https:// | ||
====== VII. References ====== | ====== VII. References ====== | ||
+ | |||
+ | * Pololu, “VL53L0X-arduino/ | ||
+ | * “Find_peaks#, | ||
+ | |||
+ | |||
amc/ss2024/irrigantion_cart_nozzle/start.1722380287.txt.gz · Last modified: 2024/07/31 00:58 by amr.abdelkhalek