Arduino CO2-sensor en CO2-toevoer

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Breezyscouting
  • Registratie: Oktober 2012
  • Laatst online: 23-03-2021
Beste Tweakers,

Ik heb vandaag 2 vraagjes voor jullie, ze zijn misschien aardig simpel, maar ik kom er momenteel echt niet uit en werk met een deadline voor komende maandag. (Ach, scholen.)

Ik maak met wat anderen een kleine kas waarin we wat spinazie gaan laten groeien, we willen hierbij een waarde van 1300ppm CO2 hebben. Dit kunnen we natuurlijk aanvoeren door zoutzuur op marmer te druppelen. Maar dat deel is nu niet belangrijk, alleen hoe we dit doen: Met een spuit als de onderstaande, waar ik op het tandwiel een stappenmotor aan ga sluiten.

(Plaatje komt binnenkort!)

Eerst gooi ik maar eens wat code jullie kant op:

Dit is de code die ik momenteel op mijn Arduino laat draaien, een licht aangepaste versie van een standaardcode voor mijn CO2-sensor:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
 #include <Wire.h>                                               // Wire bibliotheek
#include <LiquidCrystal_I2C.h>                                  // I2C lCD bibliotheek
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // I2C adres

/************************Hardware Related Macros************************************/
#define         MG_PIN                       (0)     //define which analog input channel you are going to use
#define         BOOL_PIN                     (2)
#define         DC_GAIN                      (8.5)   //define the DC gain of amplifier


/***********************Software Related Macros************************************/
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interval(in milisecond) between each samples in 
                                                     //normal operation

/**********************Application Related Macros**********************************/
//These two values differ from sensor to sensor. user should derermine this value.
#define         ZERO_POINT_VOLTAGE           (0.324) //define the output of the sensor in volts when the concentration of CO2 is 400PPM
#define         REACTION_VOLTGAE             (0.020) //define the voltage drop of the sensor when move the sensor from air into 1000ppm CO2

/*****************************Globals***********************************************/
float           CO2Curve[3]  =  {2.602,ZERO_POINT_VOLTAGE,(REACTION_VOLTGAE/(2.602-3))};   
                                                     //two points are taken from the curve. 
                                                     //with these two points, a line is formed which is
                                                     //"approximately equivalent" to the original curve.
                                                     //data format:{ x, y, slope}; point1: (lg400, 0.324), point2: (lg4000, 0.280) 
                                                     //slope = ( reaction voltage ) / (log400 &#8211;log1000) 


void setup()
{
    lcd.begin(16,2);                            // initialiseer de lcd voor 16 chars 2 line
    lcd.backlight();                            // Zet de backlight aan

    pinMode(BOOL_PIN, INPUT);                        //set pin to input
    digitalWrite(BOOL_PIN, HIGH);                    //turn on pullup resistors

   Serial.print("MG-811 Demostration\n");                
}

void loop()
{
    int percentage;
    float volts;
    
   
    volts = MGRead(MG_PIN);
    lcd.setCursor(0,0);
    lcd.print( "Voltage: " );
    lcd.print(volts); 
    lcd.print( "V           " );
    
    percentage = MGGetPercentage(volts,CO2Curve);
    lcd.setCursor(0,1);
    lcd.print("CO2: ");
    if (percentage == -1) {
        lcd.print( "<400" );
    } else {
        lcd.print(percentage);
    }
    lcd.print( "ppm" );  
    
    delay(200);
}


/*****************************  MGRead *********************************************
Input:   mg_pin - analog channel
Output:  output of SEN-000007
Remarks: This function reads the output of SEN-000007
************************************************************************************/ 
float MGRead(int mg_pin)
{
    int i;
    float v=0;

    for (i=0;i<READ_SAMPLE_TIMES;i++) {
        v += analogRead(mg_pin);
        delay(READ_SAMPLE_INTERVAL);
    }
    v = (v/READ_SAMPLE_TIMES) *5/1024 ;
    return v;  
}

/*****************************  MQGetPercentage **********************************
Input:   volts   - SEN-000007 output measured in volts
         pcurve  - pointer to the curve of the target gas
Output:  ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm) 
         of the line could be derived if y(MG-811 output) is provided. As it is a 
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic 
         value.
************************************************************************************/ 
int  MGGetPercentage(float volts, float *pcurve)
{
   if ((volts/DC_GAIN )>=ZERO_POINT_VOLTAGE) {
      return -1;
   } else { 
      return pow(10, ((volts/DC_GAIN)-pcurve[1])/pcurve[2]+pcurve[0]);
   }
}


De volgende code is de code die ik gebruik om mijn stappenmotor aan te sturen, degene die werkt met mijn stappenmotortje. Ik heb overigens al mijn info en code van Bret Stateham, die twee geweldige video's heeft over de werking en het aansturen van de 28BYJ-48 stappenmotor met een ULN2003-driverboard. Hier kun je ook alle beschikbare code vinden, evenals door Bret Stateham.

Deze manuele code werkt perfect:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
 //Put all the pins in an array to make them easy to work with
int pins[] {
    2,  //IN1 on the ULN2003 Board, BLUE end of the Blue/Yellow motor coil
    3,  //IN2 on the ULN2003 Board, PINK end of the Pink/Orange motor coil
    4,  //IN3 on the ULN2003 Board, YELLOW end of the Blue/Yellow motor coil
    5   //IN4 on the ULN2003 Board, ORANGE end of the Pink/Orange motor coil
};

//Define the wave drive sequence.  
//With the pin (coil) states as an array of arrays
int waveStepCount = 4;
int waveSteps[][4] = {
    {HIGH,LOW,LOW,LOW},
    {LOW,HIGH,LOW,LOW},
    {LOW,LOW,HIGH,LOW},
    {LOW,LOW,LOW,HIGH}
  };

//Define the full step sequence.  
//With the pin (coil) states as an array of arrays
int fullStepCount = 4;
int fullSteps[][4] = {
    {HIGH,HIGH,LOW,LOW},
    {LOW,HIGH,HIGH,LOW},
    {LOW,LOW,HIGH,HIGH},
    {HIGH,LOW,LOW,HIGH}
  };


//Keeps track of the current step.
//We'll use a zero based index. 
int currentStep = 0;

//Keeps track of the current direction
//Relative to the face of the motor. 
//Clockwise (true) or Counterclockwise(false)
//We'll default to clockwise
bool clockwise = true;

// How many steps to go before reversing, set to zero to not bounce.
//int targetSteps = 0;  //targetSteps 0 means the motor will just run in a single direction.
int targetSteps = 2048;  //2049 steps per rotation when wave or full stepping
//int targetSteps = 4096;  //4096 steps per rotation when half stepping

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);  
  
  for(int pin = 0; pin < 4; pin++) {
    pinMode(pins[pin], OUTPUT);
    digitalWrite(pins[pin], LOW);
  }
}

void step(int steps[][4], int stepCount) {
  //Then we can figure out what our current step within the sequence from the overall current step
  //and the number of steps in the sequence
  int currentStepInSequence = currentStep % stepCount;
  
  //Figure out which step to use. If clock wise, it is the same is the current step
  //if not clockwise, we fire them in the reverse order...
  int directionStep = clockwise ? currentStepInSequence : (stepCount-1) - currentStepInSequence;  

  //Set the four pins to their proper state for the current step in the sequence, 
  //and for the current direction
  for(int pin=0; pin < 4; pin++){
    digitalWrite(pins[pin],steps[directionStep][pin]);
  }  
}

void loop() {
 
  //Comment out the Serial prints to speed things up
  //Serial.print("Step: ");
  //Serial.println(currentStep);
  
  //Get a local reference to the number of steps in the sequence
  //And call the step method to advance the motor in the proper direction

  //Wave Drive
  //int stepCount = waveStepCount;
  //step(waveSteps,waveStepCount);
    
  //Full Step
  int stepCount = fullStepCount;
  step(fullSteps,fullStepCount);

  // Increment the program field tracking the current step we are on
  ++currentStep;
  
  // If targetSteps has been specified, and we have reached
  // that number of steps, reset the currentStep, and reverse directions
  if(targetSteps != 0 && currentStep == targetSteps){
    currentStep = 0;
    clockwise = !clockwise;
  } else if(targetSteps == 0 && currentStep == stepCount) {
    // don't reverse direction, just reset the currentStep to 0
    // resetting this will prevent currentStep from 
    // eventually overflowing the int variable it is stored in.
    currentStep = 0;
  }
  
  //2000 microseconds, or 2 milliseconds seems to be 
  //about the shortest delay that is usable.  Anything
  //lower and the motor starts to freeze. 
  //delayMicroseconds(2250);
  delay(2);
}


Maar deze code, waarbij hij de (jaja, door mij 100% zeker juist geïnstalleerde) AccelStepper library gebruikt, doet het dan weer niet:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 #include <AccelStepper.h>
#define HALFSTEP 8
#define FULLSTEP 4

// You need the AccelStepper library for this sketch to run.  You can get it from here: http://aka.ms/AccelStepper

// The AccelStepper constructor expects the "pins" specified to be the ends of each coil respectively.
// First the ends of the Blue/Yellow coil, then the ends of the Pink/Orange coil (Blue,Yellow,Pink,Orange)

// However, 28BYJ connector, ULN2003 board, and our current configuration is that pins are arranged in the proper FIRING order, 
// Blue, Pink, Yellow, Orange.

// No biggie, that just means that we need to pay attention to what pins on our Arduino,
// map to which ends of the coils, and pass the pin numbers in in the proper sequence.  

// To help with that, I will specify my pin variables based on their color.

#define blue 2
#define pink 3
#define yellow 4
#define orange 5

//Keeps track of the current direction
//Relative to the face of the motor. 
//Clockwise (true) or Counterclockwise(false)
//We'll default to clockwise
bool clockwise = true;

// How many steps to go before reversing
int targetPosition = 2048;  //2049 steps per rotation when wave or full stepping
// int targetPosition = 4096;  //4096 steps per rotation when half stepping

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
// Notice, I'm passing them as Blue, Yellow, Pink, Orange (coil ends order) not
// Blue, Pink, Yellow, Orange (firing order). 
AccelStepper stepper1(HALFSTEP, blue, yellow, pink, orange);

void setup() {
  //Set the initial speed (read the AccelStepper docs on what "speed" means
  stepper1.setSpeed(50.0);         
  //Tell it how fast to accelerate
  stepper1.setAcceleration(50.0); 
  //Set a maximum speed it should exceed 
  stepper1.setMaxSpeed(4000.0);      
  //Tell it to move to the target position
  stepper1.moveTo(targetPosition);   

}

void loop() {

  clockwise = true;
  //Check to see if the stepper has reached the target:
  if(stepper1.distanceToGo() == 0){
    if(clockwise == true){
      clockwise = false;  //Go counterclockwise now
      stepper1.moveTo(0); //Go back to the "home" (original) position
    } else {
      clockwise = true;   //Go clockwise now
      stepper1.moveTo(targetPosition);  //Go to the target position
    }
  }
  
  //If the stepper still needs to move (distanceToGo() != 0)
  //continue to advance (step) the motor
  stepper1.run();
}


Als ik deze code run beweegt het motortje afentoe een beetje. Het kan natuurlijk zijn dat het te snel gaat en de motor niet lang genoeg de tijd krijgt om naar de beoogde positie te gaan en daarom "freezed", maar ook als ik de speed of acceleration verander blijft dit probleem bestaan.

Ik heb eerder gezegd dat ik op basis van al het bovenstaande 2 hulpvragen heb.

Waarvan 1:
Ik wil afhankelijk van mijn sensorwaarde dat de stappenmotor naar links beweegt, ik wil dit doen wanneer de sensorwaarde onder de 1100 a 1200 PPM uitkomt. Ik kan een if-statement maken, maar de stappenmotor zelf aansturen vind ik nog aardig uitdagend, dus als er een held van een Tweaker is die me ermee kan helpen, zou dat superfijn zijn.

2:
Mijn tweede vraag is er eentje waar ik wel wat meer over gelezen heb, en toen ik voor het huidige project aan het werk was ook gezien heb.

Ik moet denk ik mijn delays gaan vervangen voor millis, want toen ik met de servo bezig was liep er (natuurlijk) een loop, en op het moment dat hij bij het deel van de servo aankwam, gingen de CO2-metingen niet door.
Naar wat ik ervan begrijp blijft je code bij een delay ook echt op dat stuk hangen en gebruikt het de gehele processor, waardoor de metingen niet doorgaan. Bij "millis" zou de processor onthouden hoelang hij een bepaald proces moet blijven uitvoeren en ondertussen doorgaan met het andere.


Als iemand me zou kunnen helpen, zou dat superfijn zijn. Ik kan 2 oplossingen heel erg waarderen: Leer het me of schrijf het bij in de code, die je hier kunt aanpassen.

Alvast bedankt mede-Tweakers!
Diego

PS: Kan een mod de topictitel veranderen? CO2 is duidelijk genoeg en de UBB doet het natuurlijk niet in de titel.. :F

Alle reacties


Acties:
  • 0 Henk 'm!

  • Lennyz
  • Registratie: Januari 2010
  • Laatst online: 25-09 09:49
Wat is de reden dat je perse die andere library wilt gebruiken? Waarom gebruik je niet de code die je wel werkend kan krijgen?

Het gebruik van delay zal niet zo'n probleem zijn aangezien het weinig verschil zal maken of je iedere seconde of iedere twee seconden een sample neemt. Dat neemt niet weg dat je het beste gewoon delay kunt vermijden natuurlijk.

Even je twee vragen in volgorde:

1. Waar is je code? Je weet al hoe je het moet oplossen, dus waarom probeer je het dan niet gewoon?

2. Even het voorbeeld blink without delay bestuderen in de Arduino IDE.