46
edits
No edit summary |
No edit summary |
||
Line 16: | Line 16: | ||
==Technical implementation== | ==Technical implementation== | ||
[[File:Seminar 2.jpg|left|thumb| | [[File:Seminar 2.jpg|left|thumb|396x396px]] | ||
===Embedded systems development === | ===Embedded systems development === | ||
During our project, we used Visual Studio Code and Arduino to program and control motors based on sensor data. Our first challenge was to determine how the motor should move. We aimed to ensure that the motors moved only once per activation, producing a single tone. To achieve this, we created an initial test code to establish how to instruct the motor to move right when it was on the left and vice versa. | |||
Next, we needed to develop a pattern to simulate incoming sensor data. The second test code introduced random numbers to help us determine a trigger value for the motors. This was combined with our previous motor movement code to create a preliminary response system. | |||
We then worked on enabling two motors to move independently. To accomplish this, we implemented two different random numbers so that each motor would move at different trigger values. Adjustments were made to delay times to introduce a more natural, randomized effect. | |||
To acquire real sensor data, we opted for an MQ-2 gas sensor, which detects combustible gases. We initially attempted to retrieve analog output values from one sensor. Since the raw sensor data wasn’t as representative as we needed, we decided to convert the readings into ppm (parts per million) for more meaningful analysis. | |||
The next step was to replace our previously used random numbers with actual gas concentration values measured by the sensor. We then expanded the system to incorporate six sensors and six motors, which required multiple iterations to perfect. A major challenge was implementing all sensor values, motors, and their corresponding variables into a function that allowed each sensor-motor pair to operate independently. We replaced the general delay time in the loop with millis() to enhance performance and flexibility. | |||
After measuring the gas concentrations produced by plants over time, we made several adjustments to optimize the installation. Each motor was assigned an individual trigger value based on the gas readings from its respective sensor. Since sensor readings were taken at short intervals and did not fluctuate significantly, motors would have been triggered too frequently, leading to excessive noise. To mitigate this, we introduced individual delay times for each motor before they could be triggered again. To create a more natural and less predictable sound pattern, we introduced a "random factor." This factor was recalculated with each sensor reading and multiplied by the motor’s delay time, ensuring a more varied and pleasant auditory experience. | |||
Debugging print commands were added to the code to help monitor sensor functionality when connected to a computer. These were primarily for troubleshooting and not necessary for the final public installation. Although the code could have been optimized for brevity, we chose to keep it more detailed to maintain a clear overview of all sensors, motors, and timing adjustments. In the end, our system successfully produced tones in a random frequency, creating a dynamic and immersive experience. | |||
===Code=== | === Technology === | ||
<small>(written by Hanna)</small> | |||
* ESP32 | |||
* mq-2 sensor for combustible gas | |||
* SG90 9g Micro Servo | |||
=== Code === | |||
===== For the platformio.ini: ===== | |||
<syntaxhighlight lang="arduino"> | |||
[env:esp32dev] | |||
platform = espressif32 | |||
board = esp32dev | |||
framework = arduino | |||
lib_deps = roboticsbrno/ServoESP32@1.0.3 | |||
monitor_speed = 9600 | |||
</syntaxhighlight> | |||
===== Fort he main.cpp: ===== | |||
<syntaxhighlight lang="arduino"> | |||
#include <Arduino.h> | |||
// include the servo library | |||
#include <Servo.h> | |||
// timing | |||
unsigned long currentTime = 0; | |||
unsigned long lastTimeA = 0; | |||
unsigned long lastTimeB = 0; | |||
unsigned long lastTimeC = 0; | |||
unsigned long lastTimeD = 0; | |||
unsigned long lastTimeE = 0; | |||
unsigned long lastTimeF = 0; | |||
const int baseServoDelayTimeA = 17300; | |||
const int baseServoDelayTimeB = 11020; | |||
const int baseServoDelayTimeC = 15400; | |||
const int baseServoDelayTimeD = 12800; | |||
const int baseServoDelayTimeE = 8400; | |||
const int baseServoDelayTimeF = 6300; | |||
float randMultiplier = 1.0; | |||
long randNumber; | |||
//sensors | |||
const float sensorTriggerValueA = 700; | |||
const float sensorTriggerValueB = 520; | |||
const float sensorTriggerValueC = 650; | |||
const float sensorTriggerValueD = 880; | |||
const float sensorTriggerValueE = 950; | |||
const float sensorTriggerValueF = 1100; | |||
float getSensorValuePpm (int sensorPin); | |||
const int sensorA = 36; | |||
const int sensorB = 39; | |||
const int sensorC = 34; | |||
const int sensorD = 35; | |||
const int sensorE = 32; | |||
const int sensorF = 33; | |||
float gasValueSensorA = getSensorValuePpm (sensorA); | |||
float gasValueSensorB = getSensorValuePpm (sensorB); | |||
float gasValueSensorC = getSensorValuePpm (sensorC); | |||
float gasValueSensorD = getSensorValuePpm (sensorD); | |||
float gasValueSensorE = getSensorValuePpm (sensorE); | |||
float gasValueSensorF = getSensorValuePpm (sensorF); | |||
//servos | |||
const int servoPinA = 19; | |||
const int servoPinB = 18; | |||
const int servoPinC = 05; | |||
const int servoPinD = 17; | |||
const int servoPinE = 16; | |||
const int servoPinF = 04; | |||
Servo servoA; | |||
Servo servoB; | |||
Servo servoC; | |||
Servo servoD; | |||
Servo servoE; | |||
Servo servoF; | |||
boolean isLeftA; | |||
boolean isLeftB; | |||
boolean isLeftC; | |||
boolean isLeftD; | |||
boolean isLeftE; | |||
boolean isLeftF; | |||
//function declarations | |||
void playSound(unsigned long &lastTime, int sensorPin, Servo &servo, float &gasValueSensor, boolean &isLeft, int baseServoDelayTime, float sensorTriggerValue); | |||
float getSensorValuePpm (int sensorPin); | |||
void setup() { | |||
analogSetAttenuation(ADC_11db); | |||
Serial.begin(9600); | |||
servoA.attach(servoPinA); | |||
servoA.write(30); | |||
isLeftA = true; | |||
servoB.attach(servoPinB); | |||
servoB.write(30); | |||
isLeftB = true; | |||
servoC.attach(servoPinC); | |||
servoC.write(30); | |||
isLeftC = true; | |||
servoD.attach(servoPinD); | |||
servoD.write(30); | |||
isLeftD = true; | |||
servoE.attach(servoPinE); | |||
servoE.write(30); | |||
isLeftE = true; | |||
servoF.attach(servoPinF); | |||
servoF.write(30); | |||
isLeftF = true; | |||
} | |||
void loop() { | |||
currentTime = millis(); | |||
playSound(lastTimeA, sensorA, servoA, gasValueSensorA, isLeftA, baseServoDelayTimeA, sensorTriggerValueA); | |||
playSound(lastTimeB, sensorB, servoB, gasValueSensorB, isLeftB, baseServoDelayTimeB, sensorTriggerValueB); | |||
playSound(lastTimeC, sensorC, servoC, gasValueSensorC, isLeftC, baseServoDelayTimeC, sensorTriggerValueC); | |||
playSound(lastTimeD, sensorD, servoD, gasValueSensorD, isLeftD, baseServoDelayTimeD, sensorTriggerValueD); | |||
playSound(lastTimeE, sensorE, servoE, gasValueSensorE, isLeftE, baseServoDelayTimeE, sensorTriggerValueE); | |||
playSound(lastTimeF, sensorF, servoF, gasValueSensorF, isLeftF, baseServoDelayTimeF, sensorTriggerValueF); | |||
} | |||
//functions | |||
void playSound(unsigned long &lastTime, int sensorPin, Servo &servo, float &gasValueSensor, boolean &isLeft, int baseServoDelayTime, float sensorTriggerValue){ | |||
//generate multiplier and adjust delaytime | |||
randMultiplier = 0.7 + (random(0, 341) / 100.0); | |||
int adjustedDelayTime = baseServoDelayTime * randMultiplier; | |||
if (currentTime - lastTime >= adjustedDelayTime){ | |||
// check if timing works | |||
Serial.print("Random delayTime"); | |||
Serial.println(adjustedDelayTime); | |||
Serial.println("Triggering sensor reaading"); | |||
gasValueSensor = getSensorValuePpm(sensorPin); | |||
// check sensor value | |||
Serial.print("Sensor Value: "); | |||
Serial.println(gasValueSensor); | |||
if (gasValueSensor > sensorTriggerValue){ | |||
Serial.println("Triggering servo"); | |||
// move servo to play sound | |||
if (isLeft == true){ | |||
servo.write(0); | |||
isLeft = false; | |||
Serial.println("right"); | |||
} | |||
else{ | |||
servo.write(30); | |||
isLeft = true; | |||
Serial.println("left"); | |||
} | |||
Serial.println("Servo moved. Last Time updated."); | |||
} | |||
// update lastTime | |||
lastTime = currentTime; | |||
} | |||
} | |||
float getSensorValuePpm (int sensorPin) { | |||
float voltage = analogRead(sensorPin) * (5.0 / 1023.0); | |||
float RS_air = 10.0; | |||
float RL = 2.0; | |||
float ratio = RL / RS_air; | |||
float RS = ((5.0 / voltage) - 1.0) * RL; | |||
float ppm = 1000.0 * pow((RS / RS_air), ratio); | |||
return ppm; | |||
} | |||
</syntaxhighlight><small>(written by Hanna)</small> | |||
==Manual construction == | ==Manual construction == |
edits