Go Down

Topic: Driving Comp Air Engine with Solenoids and Arduino (Read 7635 times) previous topic - next topic

MI_Troll

Better yet.  Make a one tooth wheel that transitions at TDC/BDC.  When it's high you are on power stroke cyl1, when it's low you are on exhaust stroke.  

Newman180

Thank you for your suggestions  MI_Troll.
As Richard has pointed out, I am using a similar system.

Newman180

Richard, I'm having an issue with the code for when to fire the solenoids. At the moment I haven't switched out of degrees. I will when I get the bugs worked out.

Can you look at my software forum post and give me some suggestions?
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1290052524/13#13

thanks

gardner

Quote
MI_Troll
1) 4 cylinder engine


Funny.  In my mind's eye I was picturing a 2 cylinder double-acting double-expansion configuration.

Newman180

Quote
Can you post the latest version of the whole code somewhere? I am reluctant to try to piece together what I think it might be from the bits and pieces I am seeing in that thread.


Ya, np.

Code: [Select]
volatile byte eventcount; // Assinging the Count Feature
unsigned int rt; // Rotation Time
unsigned int degree; // Position of Piston
unsigned int degree2;
unsigned int degree3;
unsigned int degree4;
unsigned int rpm; // RPM
unsigned long timeold; // Previous time Hall Sensor Picked up
const int So17Pin = 3; // Solenoids 1 and 7 assigned to Pin 3
const int So35Pin = 4; // Solenoids 3 and 5 assigned to Pin 4
const int So28Pin = 5; // Solenoids 2 and 8 assigned to Pin 5
const int So46Pin = 6; // Solenoids 4 and 6 assigned to Pin 6
const int buttonPin = 13; // Button For Switching "Valve Open Time" Percent
const int button2Pin = 14; // Button For Start Mode Intake 1+7
const int button3Pin = 15; // Button For Start Mode Intake 3+5
int buttonPushCounter = 0;   // counter for the number of button presses--- used with button for "Valve Open Time" Percent
int buttonState = 0;         // current state of the button
int button2State = 0;        // current state of the button 2
int button3State = 0;        // current state of  the button 3
int lastButtonState = 0;     // previous state of the button
int lastButton2State = 0;     // previous state of the button 2
int lastButton3State = 0;     // previous state of the button 3

void setup()
{
  Serial.begin(9600); // Communicate to Serial Port
  pinMode (So17Pin, OUTPUT); // Solenoid 1+7 as Output
  pinMode (So35Pin, OUTPUT); // Solenoid 3+5 as Output
  pinMode (So28Pin, OUTPUT); // Solenoid 2+8 as Output
  pinMode (So46Pin, OUTPUT); // Solenoid 4+6 as Output
  pinMode(buttonPin, INPUT); // Button for "Valve Open Time" as Input
  pinMode(button2Pin, INPUT); // Button For Start Mode 1+7 Intake
  pinMode(button3Pin, INPUT); // Button For Start Mode 3+5 Intake
  attachInterrupt(0, event_count, RISING); // Interrupt 0 is Pin 2 Hall Effect Sensor


}
 void loop()
 {
   if (eventcount >= 1) {
  // Calculate position of piston
    rt = ((micros() - timeold)/ eventcount)/360; // Time Between Each Hall Pulse
    // Time Between Each Hall Pulse Divided by ( 360 Degrees)--- Time for 1 degree of rotation
   
    timeold = micros();
    eventcount = 0;        
      }
   
  //-------------------------------------------------------------------------------------- START MODE
 
   if (rt == 0)  // If Device is not spinning then Enable the Button's 2 and 3. If it is spinning Disable the Button's 2 and 3
   { Serial.println("Device Immobile");
   if (button2State != lastButton2State) // Start Mode Button2 Pressed--- Intake 1 and 7 Exhaust 4 and 6
   {
       if (button2State == HIGH) {
    digitalWrite(So17Pin, HIGH); // Fire Intake 1 and 7
    digitalWrite(So46Pin, HIGH); // Fire Exhaust 4 and  6
    Serial.println("Start In 1+7"); // Display Via Serial "Start In 1+7"
      }
    }
 
   {
   if (button3State != lastButton3State) // Start Mode Button3 Pressed--- Intake 3 and 5 Exhaust 2 and 8
   {
   
   if (button3State == HIGH) {
    digitalWrite(So35Pin, HIGH); // Fire Intake 3 and 5
    digitalWrite(So28Pin, HIGH); // Fire Exhaust 2 and 8
    Serial.println("Start In 3+5"); // Display Via Serial "Start In 1+7"
      }
    }
   }
  //------------------------------------------------------------------------------------ RUN MODE
    {
  }
 // Open for 100% Stroke Intake (1 and 7) Exhaust (4 and 6)
 
 if (degree <= ( rt*179) || (degree >= ( rt*1) ) // If the piston is inbetween 1 to 179 degrees of revolution then...
 { if (degree >= 0.00000000000000001){
    digitalWrite(So17Pin, HIGH); // Fire Solenoid 1 and 7 (Intake)
    digitalWrite(So46Pin, HIGH); // Fire Solenoid 4 and 6 (Exhaust)
    Serial.println("Intake (1,7) Exhaust (4,6) Fired 100%"); // Print Status and Percent of Valve Open
    }
 }
else {
 digitalWrite(So17Pin, LOW); // Don't Fire Solenoid 1 and 7 (Intake)
 digitalWrite(So46Pin, LOW); // Don't Fire Solenoid 4 and 6 (Exhaust)
 }
 // Open for 100% Stroke Intake (3 and 5) Exhaust (2 and 8)
 if (degree <= (rt*359) || (degree >= (rt*181)) ) // If the piston is inbetween 181 to 359 degrees of revolution then...
 { if (degree >= 0.00000000000000001){
    digitalWrite(So35Pin, HIGH); // Fire Solenoid 3 and 5 (Intake)
    digitalWrite(So28Pin, HIGH); // Fire Solenoid 2 and 8 (Exhaust)
    Serial.println("Intake (3,5) Exhaust (2,8) Fired 100%"); // Print Status and Percent of Valve Open
 }
  }
else {
 digitalWrite(So35Pin, LOW); // Don't  Fire Solenoid 3 and 5 (Intake)
  digitalWrite(So28Pin, LOW); // Don't Fire Solenoid 2 and 8 (Exhaust)
}

}

 //------------------------------------------ Button Control--- Allows the Change of How Long Valve Stays Open Per Revolution
 
  if (buttonPushCounter <= 9){
  if (buttonState != lastButtonState) // "Percent of "Valve Open Time" " Button Pressed
  {
   
   if (buttonState == HIGH) {
      buttonPushCounter++; // Update Button Counter
     Serial.print("number of button pushes:  "); // Display Via Serial "number of button pushes: "
     Serial.println(buttonPushCounter, DEC); // Display Via Serial Button Push Count
   }
   else {          
    lastButtonState = buttonState; // Stay at last button state if Button is not Pressed
   }
  }
  else {
    buttonPushCounter = 0; // Resets to 0 if it has been pressed more than 9 times
  }

//---------------- 90% Valve Open  
 if (buttonPushCounter == 1) // If button is pressed once
 {
   Serial.println("90%");
  // Open for 90% Stroke Intake (1 and 7) Exhaust (4 and 6)
  if (degree <= ( rt*161.1) || (degree >= rt*1) ){
    digitalWrite(So17Pin, HIGH);
    digitalWrite(So46Pin, HIGH);
     Serial.println("Intake (1,7) Exhaust (4,6) Fired 90%");
    }
else {
 digitalWrite(So17Pin, LOW);
 digitalWrite(So46Pin, LOW);
}
 // Open for 90% Stroke Intake (3 and 5) Exhaust (2 and 8)
 if (degree <= (rt*342.1) || (degree >= (rt*181)) ){
    digitalWrite(So35Pin, HIGH);
    digitalWrite(So28Pin, HIGH);
    Serial.println("Intake (3,5) Exhaust (2,8) Fired 90%");
    }
else {
 digitalWrite(So35Pin, LOW);
 digitalWrite(So28Pin, LOW);
}

}

//---------------- 80% Valve Open    
  if (buttonPushCounter == 2) {
    Serial.println("80%");
  // Open for 80% Stroke Intake (1 and 7) Exhaust (4 and 6)
  if (degree <= ( rt*143.2) || (degree >= rt*1) ){
    digitalWrite(So17Pin, HIGH);
    digitalWrite(So46Pin, HIGH);
     Serial.println("Intake (1,7) Exhaust (4,6) Fired 80%");
    }
else {
 digitalWrite(So17Pin, LOW);
 digitalWrite(So46Pin, LOW);
}
 // Open for 80% Stroke Intake (3 and 5) Exhaust (2 and 8)
 if (degree <= (rt*324.2) || (degree >= (rt*181)) ){
    digitalWrite(So35Pin, HIGH);
    digitalWrite(So28Pin, HIGH);
    Serial.println("Intake (3,5) Exhaust (2,8) Fired 80%");
    }
else {
 digitalWrite(So35Pin, LOW);
 digitalWrite(So28Pin, LOW);
}
}
}

 void event_count()
{
  eventcount++; // Hall Effect Count Updater
}


If you have been reading in the other thread, I'm having an issue with actually describing to the Arduino when to fire the solenoids.

I know that I want it to fire specified solenoids between rt*1 and rt*179 and other solenoids between rt*181 and rt*359.

I just don't know how to write the "if" statement to handle those simple calculations.

And yes gardner it is a 4 cylinder. Double acting was harder to build atm.

Newman180

Quote
What on earth is THAT?
You do realize that you are using an 8-bit Reduced Instruction Set MICRO-processor here?  Right?
You don't need that many zeroes even to calculate the national debt (at least not for the next few weeks).  Shocked


Haha, I was getting frustrated when the serial readout on the arduino port wasn't feeding what I wanted. Just typed a bunch of zeros

Quote

Frankly, you code just seems WAY too complex.  You should be able to do this entirely with integers.  I am suspicious of anything requiring decimals.

I agree its overly complex, so Please guide me with how to do this.
As I mentioned before, this is for my senior design for mechanical engineering. The software side was supposed to be quick and easy. Even though I've never taken a programming course, or learned any type of computer engineering, I thought it was going to be a lot easier.
I'm willing to learn though,
I'm not asking you to write it for me, but give me some examples!  ;)



Newman180

Quote
I don't know how you are calculating the valve open and close times/positions/angles? Are they fixed? Are you going to change them?

Unfortunately, the valve timings need to be adjustable to set increments. If it was always one set value, I would probably bypass the microprocessor all together...

Quote
Anyway, I would create a table of open and close values. I would make each value in integer 1000ths of a rotation (or 10ths of a percent, if you wish). So something that happens right after TDC would have a value of 0001 and something that happens just before TDC would have a value of 0999. Note that this is ~3x better resolution than using "degrees" and keeps all the math in integers.

Here is what I would do in the code, starting with the detection of TDC.
1) Subtract right now from previous TDC to establish rotation period in microseconds.
2) Store this TDC time for use next time around.
3) Multiply your table of open/close times (in 1000ths of a revolution) against the rotation period.
4) Each time one of those calculated times occurs open or close whatever valve.
5) wait for the next TDC

Great! Let me research how to set up tables, and I'll try to put one together. Thanks Richard.


Chief Ten_thumbs

Richard said:
"Here is what I would do in the code, starting with the detection of TDC.
1) Subtract right now from previous TDC to establish rotation period in microseconds.
2) Store this TDC time for use next time around.
3) Multiply your table of open/close times (in 1000ths of a revolution) against the rotation period.
4) Each time one of those calculated times occurs open or close whatever valve.
5) wait for the next TDC

I don't know why it should be any more complex than that?

Note that if the valve open/close times are fixed, you could consider just cutting a custom rotor with "teeth" at each open or close point. Then you wouldn't have to worry about extrapolating or calculating times within each resolution."
**************************
I apologize if my input seems out of line..... After 30 years in the computer industry I have come to believe strongly in the KISS principle. It is axiomatic that if the code is ugly and complex it's not ready to play.... that being said, Richard has thumbnailed a simple flow chart to conquer your timing issue.

My suggestion is to focus on the sensor position readings and the timing between pulses rather than reinventing the wheel in the code.

Back in the day we learned to "right" a logic map/flow chart before writing code......

Just sayin'  ;)

Dave

"Middle out programming is the path to insanity......"
mumbled by a Microsoft engineer sleeping under his desk circa 1995

PaulS

Quote
2) Store this TDC time for use next time around.

This is what I told you you need to do, over in the software thread. But, you weren't listening there, so I doubt you'll listen here, either.

Newman180

Quote

This is what I told you you need to do, over in the software thread. But, you weren't listening there, so I doubt you'll listen here, either.

It's not that I wasn't listening, but I think you were forgetting that I have no background in this side of engineering. Me asking a question and you responding with something other than the answer to my question got me confused and frustrated. I appreciate your input thus far and hope that you continue to give me insight. Just remember, I'm a beginner.  ;)

Newman180

Should I be using PROGMEM to create and store the tables?

gardner

Quote
Should I be using PROGMEM to create and store the tables


For tables above a few dozen bytes, yes, PROGMEM is the right way to store them. It's a little fussy to access PROGMEM, but not too bad.

Newman180

Quote

For tables above a few dozen bytes, yes, PROGMEM is the right way to store them. It's a little fussy to access PROGMEM, but not too bad.


K, Thanks. Yea I haven't found very many examples of storing large tables, so I wasn't completely sure on the method.

Newman180

Quote
How many valves do you have 8? 16? each one needs two values one for opening-time and one for closing-time.


Technically 8, but there's 2 on each pin, so the arduino thinks there are only 4.

I was thinking that I was going to make a table with values from 0001 to 0999, but just realized that I was on the wrong thought process.

Newman180

Once again, Sorry there hasn't been an update yet. Finals are around the corner, and I have been busy studying.
Hopefully I will be able to post this weekend with new code and probably more questions ;)


Go Up