Controllind solenoid using arduino two modes of operation

I have 3 solenoids that I would like to control using an arduino.

Mode 1:
when Input is HIGH (from a synthesizer) -
solenoid will pulsating at 30ms ON time in a speed determine by the potentiometer (slow(every 5 sec lets say, to fast (every 100ms)

Mode 2:
When input is HIGH (from a synthesizer) - solenoid will do one pulse of 30ms ON time
potentiometer will decide the threshold for making the pulse (acting as comparator threshold)

here is my schematics (1 channel):

you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

In your case it's also driven on timing, so for extra information and examples look at

I'd suggest you pick one of the button library such as Button in easyRun or OneButton or Toggle or EasyButton or Bounce2, ... to make your life easy

I would prefer using SPDT switch.

is wiring it as I did is not the right way?

do you mean this part?
image

yes

I guess you set pin 8 as a INPUT and you'll read either LOW or HIGH depending on the position of your button.

By default pins are INPUT but if you were not careful and set the pin to be an OUTPUT LOW and the switch were to be on VCC, you would create a short that would destroy the pin and / or the arduino.

Typically you can connect just Pin 8 --- (2) button (3) --- GND and leave sw1 not connected and set the pin 8 as INPUT_PULLUP. This way there is no risk whatsoever to create a short.

1 Like

here is the code I got so far:

#define NUM_POTS 4            // Number of pots

int heartbeatLED = 13;

const byte POT_pins[] = {A0, A1, A2, A3}; // pot analog input pins
const byte inputPIN[] = {A4, A5, A6, A7}; // input pin from synthesizer
const byte modeSwitchPin[] = {6, 7, 8, 9};     // Digital input pin for mode switch
const byte solenoidPin[] = {2, 3, 4, 5};       // Digital output pin for solenoid

const byte filterPOT = 5;  // pot filter
int lastValuePOT[NUM_POTS];


unsigned long lastPulseTime = 0;
unsigned long pulseDuration = 0;

//timing variables
unsigned long previousMillis = 0;
unsigned long heartbeatMillis;

void setup() {

  pinMode(modeSwitchPin, INPUT_PULLUP);
  pinMode(heartbeatLED, OUTPUT);

  for (byte i = 0; i < NUM_POTS; i++) {
    pinMode(POT_pins[i], INPUT);
    pinMode(inputPIN[i], INPUT);
    pinMode(solenoidPin[i], OUTPUT);
    Serial.begin(115200);
  }
}

void loop() {
  checkHeartbeatTIMER();
  for (byte i = 0; i < NUM_POTS; i++) {
    //read the stabilized analog
    int POTValue = analogRead(POT_pins[i]);

    //has analog value changed more than the filter amount ?
    if (abs(lastValuePOT[i] - POTValue) > filterPOT) {
      if (lastValuePOT[i] != POTValue) {
        //update to the new value
        lastValuePOT[i] = POTValue;
        Serial.print("POT");
        Serial.print(i + 1);
        Serial.print(" ");
        Serial.println(POTValue);
        POTValue = map(POTValue, 0, 1023, 5, 100);
        pulseDuration = map(POTValue, 0, 1023, 5, 100); // Map potentiometer value to pulse duration
        pulsateSolenoid();
      }
    }
  }
}

void pulsateSolenoid() {
  unsigned long currentTime = millis();

  if (currentTime - lastPulseTime >= pulseDuration) {
    digitalWrite(solenoidPin, HIGH);
    lastPulseTime = currentTime;
  }

  if (currentTime - lastPulseTime >= 30) {
    digitalWrite(solenoidPin, LOW);
  }
}


void checkHeartbeatTIMER() {

  //is it time to toggle the heartbeatLED ?
  if (millis() - heartbeatMillis >= 500ul) {
    //restart this TIMER
    heartbeatMillis = millis();

    //toggle the heartbeatLED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

}  //END of   checkHeartbeatTIMER()

here is the updated schematics:

it seems you have 4 times the same type of construct

you should make a class or a struct with it

class SynthesizerInterface {
  public: 
    byte potPin;
    byte inputPin;
    byte modeSwitchPin;
    byte solenoidPin;
    int lastValuePOT;

•••
};

Anyone can see whats wrong with my code?

#define NUM_POTS 1            // Number of pots

int heartbeatLED = 13;

const byte POT_pins[] = {A0, A1, A2, A3}; // pot analog input pins
const byte inputPIN[] = {A4, A5, A6, A7}; // input pin from synthesizer
const byte modeSwitchPin[] = {6, 7, 8, 9}; // Digital input pin for mode switch
const byte solenoidPin[] = {2, 3, 4, 5};   // Digital output pin for solenoid

const byte filterPOT = 5;  // pot filter
int lastValuePOT[NUM_POTS];

unsigned long lastPulseTime = 0;
unsigned long pulseDuration = 0;

// timing variables
unsigned long previousMillis = 0;
unsigned long heartbeatMillis;

void setup() {
  pinMode(heartbeatLED, OUTPUT);

  for (byte i = 0; i < NUM_POTS; i++) {
    pinMode(POT_pins[i], INPUT);
    pinMode(inputPIN[i], INPUT);
    pinMode(modeSwitchPin[i], INPUT_PULLUP);
    pinMode(solenoidPin[i], OUTPUT);
  }

  Serial.begin(115200);  // Serial initialization outside the loop
}

void loop() {
  // Your main loop code here

  // Example: Call mode1
  mode1();

  // Read and filter pot values
  for (byte i = 0; i < NUM_POTS; i++) {
    // Read the stabilized analog value
    int potValue = analogRead(POT_pins[i]);

    // Has analog value changed more than the filter amount?
    if (abs(lastValuePOT[i] - potValue) > filterPOT) {
      if (lastValuePOT[i] != potValue) {
        // Update to the new value
        lastValuePOT[i] = potValue;
        Serial.print("POT");
        Serial.print(i + 1);
        Serial.print(" ");
        Serial.println(potValue);

        // Map potValue to the pulsating rate
        int pulsatingRate = map(potValue, 0, 1023, 2000, 100); // 2000ms (2 seconds) to 100ms

        // Call function to pulsate solenoid with a fixed ON time of 30ms
        pulsateSolenoid(30, pulsatingRate);
      }
    }
  }

  // Call heartbeat function
  checkHeartbeatTIMER();

  // Add more modes or functionalities as needed
}

void mode1() {
  // Check if inputPIN is HIGH
  if (digitalRead(inputPIN[0]) == HIGH) {  // Assuming you are checking inputPIN[0] for Mode 1
    // Read potentiometer value to determine pulsating rate
    int POTValue = 1023 - analogRead(POT_pins[0]); // Assuming you are using POT_pins[0] for Mode 1

    // Has analog value changed more than the filter amount?
    if (abs(lastValuePOT[0] - POTValue) > filterPOT) {
      if (lastValuePOT[0] != POTValue) {
        // Update to the new value
        lastValuePOT[0] = POTValue;
        Serial.print("POT");
        Serial.print(1);
        Serial.print(" ");
        POTValue = map(POTValue, 0, 1023, 255, 0);
        Serial.println(POTValue);

        // Map the potValue to the pulsating rate
        int pulsatingRate = map(POTValue, 0, 1023, 2000, 100); // 2000ms (2 seconds) to 100ms

        // Call function to pulsate solenoid with a fixed ON time of 30ms
        pulsateSolenoid(30, pulsatingRate);
      }
    }
  }
}

void pulsateSolenoid(int onTime, int rate) {
  unsigned long currentTime = millis();

  if (currentTime - lastPulseTime >= rate) {
    digitalWrite(solenoidPin[0], HIGH);  // Assuming you are controlling solenoidPin[0] for Mode 1
    Serial.println("Solenoid ON");
    delay(onTime);
    digitalWrite(solenoidPin[0], LOW);
    Serial.println("Solenoid OFF");
    lastPulseTime = currentTime;
  }
}

void checkHeartbeatTIMER() {
  //is it time to toggle the heartbeatLED?
  if (millis() - heartbeatMillis >= 500ul) {
    //restart this TIMER
    heartbeatMillis = millis();

    //toggle the heartbeatLED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }
}  //END of checkHeartbeatTIMER()

this delay will kill you

as said in post #2 you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

I'm looking through the tiniest of windows, it looks plausible but I see no use of any modes or mode switching.

So it is doing something. Please say what the code does now, and describe how it is doing something it should not, or isn't doing something it should. As of this version.

Then explain again, assuming this version does what it looks like it does and that is correct for this version, how you want to modify the code - what will it do when you are finished?

a7

I try first with only 1 mode:

while input is HIGH pulse the solenoid at a speed determine by the pot with on time of 30ms

so if pot is set to speed of 1000ms the solenoid will be ON for 30ms and then OFF for 970ms. if the pot is set to 200ms the solenoid should be ON for 30ms and then OFF for 170ms. etc etc

--

it seems that when the input is HIGH the pot reading become unstable and no pulsing is accuring

so I have the following code which is working great in one of the modes:

when in mode2 that it should only pulse once when gate is HIGH the solenoid is stuck in his ON position without realising after 30ms. why?

#define SOLENOID_PIN 4    // Digital output pin for solenoid
int inputPIN = A4;        // Analog input pin for the input
int potPIN = A0;          // Analog input pin for the potentiometer
int switchPIN = 8;        // Digital input pin for the switch

unsigned long lastPulseTime = 0;
unsigned long pulseInterval = 200; // Default time between pulses
const int onTime = 30; // Constant ON time for the solenoid
bool switchStateChanged = true;

void setup() {
  pinMode(SOLENOID_PIN, OUTPUT);
  pinMode(inputPIN, INPUT);
  pinMode(potPIN, INPUT);
  pinMode(switchPIN, INPUT_PULLUP); // Internal pull-up resistor for the switch
  Serial.begin(115200);
}

void loop() {
  // Read the input
  int inputValue = digitalRead(inputPIN);
  int switchState = digitalRead(switchPIN);

  // Check if switch state has changed
  if (switchState != digitalRead(switchPIN)) {
    switchStateChanged = true;
  }
   if (inputValue == HIGH && switchState == HIGH) {
        pulsateSolenoidOnce();

   }
  

  // Check if input is HIGH and switch is pressed
  if (inputValue == HIGH && switchState == LOW) {
    // Read potentiometer value to determine time between pulses
    int potValue = analogRead(potPIN);

    // Map potValue to the pulse interval
    pulseInterval = map(potValue, 0, 1023, 50, 2000); // Adjust the range as needed

    // Call function to pulsate solenoid
    pulsateSolenoid();
  } else if (switchStateChanged) {
    Serial.println("Mode 2"); // Switch in the other position
    switchStateChanged = false; // Reset the flag

    // Call function to pulsate solenoid once in the other switch position
    pulsateSolenoidOnce();
  }
}

void pulsateSolenoid() {
  unsigned long currentTime = millis();

  if (currentTime - lastPulseTime >= pulseInterval) {
    digitalWrite(SOLENOID_PIN, HIGH);
    Serial.println("Solenoid ON");
    delay(onTime); // Constant ON time
    digitalWrite(SOLENOID_PIN, LOW);
    Serial.println("Solenoid OFF");
    lastPulseTime = currentTime;
  }
}

void pulsateSolenoidOnce() {
  digitalWrite(SOLENOID_PIN, HIGH);
  Serial.println("Solenoid ON");
  delay(onTime); // Constant ON time
  digitalWrite(SOLENOID_PIN, LOW);
  Serial.println("Solenoid OFF");
} 

Remember, you need to do the equivalent of debouncing the switch because it takes time to transition from one contact to the other and when your program reads the switch during that time, pin 2 is floating.

I was digging in and got along before I saw the above snippet.

There are only four references to the variable switchState.

You read the switchPIN into it, then immediately compare by reading the switch again.

Usually, the previous switch state is saved to compare with a new reading. This would requite the the switchState endure, so it must be a global variable or a local variable qualified as static.

I would be re-writing the sketch at this point. So I recommend that you think it out a bit.

You need to do debouncing and state change detection to develop the information that a switch has become high or low (not is high or low), and maintain a state variable that can tell you if the switch is stable and high or low.

You may benefit from using the IPO model.

Input - read all the switches and pots and whatever.

Process - decide based on the inputs and any mode selected and current progress in executing that mode (including timers) what the output should become (or remain)

Output - actually write to the outputs

Input and Output are the only code sections that use digitalWrite(), digitalRead() and analogRead().

Input also sees if any timers in progress are done.

Process deals strictly with the logic - what should the output be, is it necessary to restart any timers.

I like my state change detection as much as everyone likes her own, so try this in the simulation that is linked on the post on the thread where I threw in my version:

HTH

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.