A switch, a photocell and one output

Hi all, I have been going mad trying to figure out a way to control my project, I have some experience with programming c++ but I need some guidance on what sort of control structures I should be using to do what I want.

It consists of motor that is connected to a rotor with a cam, the cam has three lobes on it and a microswitch is turned on or off by the cam.

I am using the Arduino Uno,

The Arduino IDE is version 1.0.5

I am trying to make a program that can to the following

Step1. See if the switch is open or closed (is the rotor in the right position)

-If the switch is low then turn the relay on until the switch becomes high, after becoming high the relay is switched off. (the motor-rotor is self locking so it should not move after the motor is off)

Step 2.
-Keep the relay off
-wait 5 Minutes!

THEN!!

Step 3.check the value of the photocell!
If it is above a threshold then all is great, go to step 2.

If not! then turn the relay on until the switch goes low then stop once it becomes high again.
Go to step 2

END

What I am getting instead is that the relay will turn on or off and then will not change when the two inputs change, it stays at it’s one state and does not do anything different. I have fiddled around with the code and sometimes the relay will stay in one state ether on or off regardless of what the inputs are and will not change when the inputs change.

EDIT:

Here is my code that I have tried so far:

const int analogPin = A0;    // pin that the photosensor is attached to
const int ledPin = 9;       // pin that the relay is attached to
const int threshold = 800;   
const int buttonPin = 8;  switch for cam postion
int buttonState = 0; 

void setup() {  
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);   
    Serial.begin(9600);
}

void loop() {

  int analogValue = analogRead(analogPin);
  buttonState = digitalRead(buttonPin);  
 
  if (buttonState == HIGH && analogValue > threshold) {
    digitalWrite(ledPin, HIGH);
 }
   
if (buttonState == HIGH && analogValue < threshold) {
    digitalWrite(ledPin, HIGH);   //low light equals low value
}

if ( buttonState == LOW && analogValue < threshold) {   
   digitalWrite(ledPin, LOW);   //low light equals low value 
}

if ( buttonState == HIGH ) {
    digitalWrite(ledPin, HIGH);   //low light equals low value
delay(100);
  } 

  // print the analog value:
  Serial.println(analogValue);   
  
  delay(10);        // delay in between reads for stability
}

First, read the ‘sticky’ posting at the top of the forum page, then post

What hardware you are using (motor shield? your own motor circuit?, etc.)

How you have your hardware wired up.

The code you’ve tried (in code tags, please).

lar3ry: First, read the 'sticky' posting at the top of the forum page, then post

What hardware you are using (motor shield? your own motor circuit?, etc.)

How you have your hardware wired up.

The code you've tried (in code tags, please).

Will do! Thank you!

I have edited my first post to include the code that I am using. I am using the arduino UNO,

There is a micro switch on pin 8 (EDIT) and a photocell on analog pin 0 with a resistor going to ground for both pins, I have tested the inputs individually using ready made code and they work fine, the output is on pin 9 and is connected to an ready made optoisolated relay board.

The_Unreasonable_Man: There is a micro switch on pin 9 and a photocell on analog pin 0 with a resistor going to ground for both pins, I have tested the inputs individually using ready made code and they work fine, the output is on pin 9 and is connected to an ready made optoisolated relay board.

OK... is pin 9 wired like #1 or #2? For the photocell, instead of switch.. #1 or #2

1 -- GND_ResistorSwitch__Pin 9

2 -- GND_ResistorSwitchPin 9__+5V

lar3ry:

The_Unreasonable_Man: There is a micro switch on pin 9 and a photocell on analog pin 0 with a resistor going to ground for both pins, I have tested the inputs individually using ready made code and they work fine, the output is on pin 9 and is connected to an ready made optoisolated relay board.

OK... is pin 9 wired like #1 or #2? For the photocell, instead of switch.. #1 or #2

1 -- GND_ResistorSwitch__Pin 9

2 -- GND_ResistorSwitchPin 9__+5V

My mistake: the input is on pin 8 the output is on pin 9

Like this except it is going to pin 8

OK, when your switch is closed, it will write a HIGH to ledPin regardless of the analog read value (unless it happens to be exactly 800, which is unlikely).

Then, if the switch is open, and the analog value is less than threshhold, the motor will stop.

Then, near the end of loop(), it will again, set ledPin to HIGH reagrdless of what's on the analog pin, delay 10 milliseconds and run all that again.

You haven't shown me the photocell schematic yet.

One of the problems you may run into is that switches bounce. They will bounce for some number of milliseconds. See Nick Gammon's excellent tutorial at http://www.gammon.com.au/forum/?id=11955

Oh, you used quote tags. code tags are the # icon.

lar3ry: OK, when your switch is closed, it will write a HIGH to ledPin regardless of the analog read value (unless it happens to be exactly 800, which is unlikely).

Then, if the switch is open, and the analog value is less than threshhold, the motor will stop.

Then, near the end of loop(), it will again, set ledPin to HIGH reagrdless of what's on the analog pin, delay 10 milliseconds and run all that again.

You haven't shown me the photocell schematic yet.

One of the problems you may run into is that switches bounce. They will bounce for some number of milliseconds. See Nick Gammon's excellent tutorial at http://www.gammon.com.au/forum/?id=11955

Oh, you used quote tags. code tags are the # icon.

I am going to need to read up on the debounce, thank you for sharing that.

The photocell is wired up the same way that the switch is, the analog pin is pulled to ground by a resistor, 5v goes to the photocell and then to the analog pin A0

The device in question here is a automatic lampchanger, a turntable/rotor contains three lights that are connected to power by a commutator like arrangement like what would be found on a DC motor, a single pole double throw relay will send power to ether the light on the rotor or to a motor that spins the rotor but not both.

In order for contacts to connect on the rotor it must be in a certain position, the positions are 120 degrees apart and the microswitch will indicate when the rotor has reached the desired position.

When the switch is low it would mean the rotor is not in position, the input from the photocell is irreverent until the rotor is in position as indicated by the switch being high (the input pin is high).

after rotor is in position then the next input that matters would be the photo cell, due to the nature of the lights on the rotor a reading from the photocell should be taken after 5 minutes.

OK, but if the switch is HIGH, it will make ledPin HIGH, regardless of the voltage on the analog pin…

  if (buttonState == HIGH && analogValue > threshold) {
    digitalWrite(ledPin, HIGH);
  }

  if (buttonState == HIGH && analogValue < threshold) {
    digitalWrite(ledPin, HIGH);   //low light equals low value
  }

  if ( buttonState == LOW && analogValue < threshold) {  
    digitalWrite(ledPin, LOW);   //low light equals low value
  }

  if ( buttonState == HIGH ) {
    digitalWrite(ledPin, HIGH);   //low light equals low value
    delay(100);
  }

If buttonState is HIGH
if the first IF does not set ledPin HIGH, the second one will, and vice versa.
the fourth IF will set ledPin HIGH

If buttonState is low, the third IF will set ledPin LOW

The entire loop() code will run VERY fast, performing all tests and actions in just over 1/10 of a second. The delay(100) is will take the majority of the time in loop().

-If the switch is low then turn the relay on until the switch becomes high

Like so?

  if (buttonState == HIGH && analogValue > threshold) {
    digitalWrite(ledPin, HIGH);
 }

How does that have any bearing on a relay pin?

You CAN use names that mean something, you know.

What you describe is at state machine. It can be very accurately modeled by a state diagram (attached). Once that is done the diagram is converted into code using my statemachine library found here: http://playground.arduino.cc/Code/SMlib
Its very simple.

  • Write a short function for each state (circle) in the diagram. The type of the function is “State”
  • Create a statemachine object and designate one of the states as initial state (double circle)
  • write code inside the state functions to handle outputs and read inputs. Change the state by using the Set function
  • Put the EXEC() statement inside the loop() function. All other code must be non-blocking

This is what the attached diagram looks as code, it shoild be very clear how the diagram and the code correlate:

#include <SM.h>


SM CAM(Turn);
const int CamSwitch = 8;
const int WaitTime = 5*60*1000;//=5 min
const int Motor = 9;
const int FCThreshold = 512;

void setup(){
  pinMode(Motor, OUTPUT);
}//setup()


void loop(){
  EXEC(CAM);//run controller
}//loop()

State Turn(){
  digitalWrite(Motor, 1);//Motor on
  if(digitalRead(CamSwitch)) CAM.Set(Wait);//Cam reached
}//Turn()

State Wait(){
  digitalWrite(Motor, 0);//Motor off
  if(CAM.Timeout(WaitTime)) CAM.Set(CheckFC);//wait 5 min
}//Wait()

State CheckFC(){
  if(analogRead(A0)>FCThreshold) CAM.Set(Wait);//treshold ok
  else CAM.Set(NextCam);//treshold not ok, another cam
}//CheckFC()

State NextCam(){
  digitalWrite(Motor,1);//turn motor back on
  if(!digitalRead(CamSwitch)) CAM.Set(Turn);// turn cam past switch
}//Nextcam()

cam controller state diagram.png

nilton61:
What you describe is at state machine. It can be very accurately modeled by a state diagram (attached). Once that is done the diagram is converted into code using my statemachine library found here: http://playground.arduino.cc/Code/SMlib
Its very simple.

  • Write a short function for each state (circle) in the diagram. The type of the function is “State”
  • Create a statemachine object and designate one of the states as initial state (double circle)
  • write code inside the state functions to handle outputs and read inputs. Change the state by using the Set function
  • Put the EXEC() statement inside the loop() function. All other code must be non-blocking

This is what the attached diagram looks as code, it shoild be very clear how the diagram and the code correlate:

#include <SM.h>

SM CAM(Turn);
const int CamSwitch = 8;
const int WaitTime = 5601000;//=5 min
const int Motor = 9;
const int FCThreshold = 512;

void setup(){
 pinMode(Motor, OUTPUT);
}//setup()

void loop(){
 EXEC(CAM);//run controller
}//loop()

State Turn(){
 digitalWrite(Motor, 1);//Motor on
 if(digitalRead(CamSwitch)) CAM.Set(Wait);//Cam reached
}//Turn()

State Wait(){
 digitalWrite(Motor, 0);//Motor off
 if(CAM.Timeout(WaitTime)) CAM.Set(CheckFC);//wait 5 min
}//Wait()

State CheckFC(){
 if(analogRead(A0)>FCThreshold) CAM.Set(Wait);//treshold ok
 else CAM.Set(NextCam);//treshold not ok, another cam
}//CheckFC()

State NextCam(){
 digitalWrite(Motor,1);//turn motor back on
 if(!digitalRead(CamSwitch)) CAM.Set(Turn);// turn cam past switch
}//Nextcam()

Sorry about resurrecting this old thread but I have used the code that you posted and it worked! I have built the device and you would like I can send a picture of it to you via a private message. I really appreciate your help in all of this.

I do have one small problem that I have not been able to solve or find an answer to elsewhere, When the device turns on the first thing that it does is change the bulb, How can I change the program so that it will start in the “wait” state instead of the “Turn” state? I have tried simply rearranging the order of the states int the loop but it did not work correctly, am I missing something?

Sorry bout the late reply. I'm not very active here at the moment. In order to change the starting state from "Turn" to "Wait" you change the definition of the state machine object from

SM CAM(Turn);

to

SM CAM(Wait);

This because the state machine needs a initial state when beginning execution