Need some help with code for my project

Hello,

I'm creating an self opening mechanism that is supposed to start opening once the sun is detected (even if its a bit cloudy) . I am using a stepper motor (Hanpose 17HS) for the opening pourpous and photoresistor for sun detection. My stepper motor is run through TMC2209 driver and also will include a switch on top of mechanism that will 'signalize' that its on the right spot and is supposed to stop turning at that point. I've managed to create a code that starts to spin motor in 1 direction then after a while it goes to another direction but the idea of photoresistor making stepper motor spin once the sun is detected isn't working out, in fact no matter if its dark or sun it will spin left/right no matter what. I am not an expert in coding nor I have ever had any kind of classes, besides what I watched on internet and what I managed to figure out so far, which is why I'd like to ask someone if you can point out my mistakes so I can try to improve on my own. Thank you !

#define step_pin 6  
#define dir_pin 5     
#define home_switch 3 

const int minReading = 55; 
const int maxReading = 25; 
int photoresistorPin = A0;
int decValue = 0;
unsigned int x=65535;
int analogValue = 0;
int delay_master = 1000;
int steps;


void setup() {  
  pinMode(dir_pin, OUTPUT);
  pinMode(step_pin, OUTPUT);
  pinMode(home_switch, INPUT_PULLUP);   
  pinMode(photoresistorPin, INPUT);
  Serial.begin(9600);
 
  while (digitalRead(home_switch)) {  
    digitalWrite(dir_pin, HIGH);     
    digitalWrite(step_pin, HIGH);
    delayMicroseconds(1000);
    digitalWrite(step_pin, LOW);
    delayMicroseconds(1000);
  }
  steps = 0; 
delay(10000);
}
void loop() {
  decValue = analogRead(photoresistorPin);
  x = map(decValue, 0, 1023, 0, 65000);
  x = round(x/650.0);
  Serial.println(x);
int  y = 0;
    for(int y = 0; y < 14600; y++) {
      if (( y <= 7300) && (x < minReading)) {
      digitalWrite(dir_pin,LOW); 
     }                           
      else {
      digitalWrite(dir_pin,HIGH);
     }

    digitalWrite(step_pin,HIGH); 
    delayMicroseconds(delay_master);   
    digitalWrite(step_pin,LOW); 
    delayMicroseconds(delay_master); 
 }
  //delay(1000); 
}

x is an integer. There's very little point doing floating point maths on it or expecting floating point results.

 x = map(decValue, 0, 1023, 0, 65000);
  x = round(x/650.0);

If you want a value in the range 0 to 100, why not just...

 x = map(decValue, 0, 1023, 0,100);

No need to have the "int y=0;" here. The for loop declares a new y and sets it to zero for you...

int  y = 0;
    for(int y = 0; y < 14600; y++) {

Also you have made the mistake of having two "int y" statements in your program. You now have two different "y" variables and no way to tell them apart. Never declare (use of the "int" variable type name) variables with the same name more than once. The compiler knows what you mean, but you're likely to get in an awful pickle.

Probably a for loop is the wrong way to go here. Also the y <= 7300 test in there is changing direction of the motor half way through the loop. Not sure why you want to do that.

Better logic would be (note this is pseudo code, not actual C/C++ code)...

IF sensor indicates daylight (e.g. > 75)
  daylight = true;
IF sensor indicates darkness (e.g. < 25)
  daylight = false;

IF daylight AND NOT at open end stop
   set OPEN direction
   do *ONE* step of motor

IF NOT daylight AND NOT at close end stop
   set CLOSE direction
   do *ONE* step of motor

Now you will see that just by having this code in loop() the motor will turn if necessary in the correct direction until the end stop is reached.

If you don't have an open end stop sensor you will need to keep track of the number of steps to determine "open" and hope you don't miss any steps or over step...

IF sensor indicates daylight (e.g. > 75)
  daylight = true;
IF sensor indicates darkness (e.g. < 25)
  daylight = false;

IF at close end stop
  stepperPos = 0;

IF daylight AND stepperPos < MAX_STEPS
   set OPEN direction
   do *ONE* step of motor
   stepperPos++;

IF NOT daylight AND stepperPos > 0
   set CLOSE direction
   do *ONE* step of motor
   IF stepperPos > 1
      stepperPos--;

pcbbc:
x is an integer. There's very little point doing floating point maths on it or expecting floating point results.

 x = map(decValue, 0, 1023, 0, 65000);

x = round(x/650.0);



If you want a value in the range 0 to 100, why not just...


x = map(decValue, 0, 1023, 0,100);




No need to have the "int y=0;" here. The for loop declares a new y and sets it to zero for you...


int  y = 0;
    for(int y = 0; y < 14600; y++) {



Also you have made the mistake of having two "int y" statements in your program. You now have two different "y" variables and no way to tell them apart. Never declare (use of the "int" variable type name) variables with the same name more than once. The compiler knows what you mean, but you're likely to get in an awful pickle.

Probably a for loop is the wrong way to go here. Also the y <= 7300 test in there is changing direction of the motor half way through the loop. Not sure why you want to do that.

Better logic would be (note this is pseudo code, not actual C/C++ code)...


IF sensor indicates daylight (e.g. > 75)
  daylight = true;
IF sensor indicates darkness (e.g. < 25)
  daylight = false;

IF daylight AND NOT at open end stop
  set OPEN direction
  do ONE step of motor

IF NOT daylight AND NOT at close end stop
  set CLOSE direction
  do ONE step of motor



Now you will see that just by having this code in loop() the motor will turn if necessary in the correct direction until the end stop is reached.

If you don't have an open end stop sensor you will need to keep track of the number of steps to determine "open" and hope you don't miss any steps or over step...


IF sensor indicates daylight (e.g. > 75)
  daylight = true;
IF sensor indicates darkness (e.g. < 25)
  daylight = false;

IF at close end stop
  stepperPos = 0;

IF daylight AND stepperPos < MAX_STEPS
  set OPEN direction
  do ONE step of motor
  stepperPos++;

IF NOT daylight AND stepperPos > 0
  set CLOSE direction
  do ONE step of motor
  IF stepperPos > 1
      stepperPos--;

Hi and thank you for replying. I have taken your advice and did some changes to the code, we could say that few things got resolved but I believe I have new problems at this point. Through serial port i can see that photodetector is actually reading the values which sure is an improvement compared to before also the stepper motor is standing at 1 point slowly vibrating but not moving even if I expose the photodetector to sun/dark and press/unpress the switch, I'll post the new code and make my current schematic on fritzing and post it here hopefully it might tell you something more then just words .

#include <Stepper.h>
//Defining pins
#define step_pin 6 // connected with step pin on driver
#define dir_pin 5 // connected with dir pin on driver
#define home_switch 3

const int stepsPerRevolution = 200;
const int maxReading = 55; // for opening
const int minReading = 25; // for closing
unsigned int x=100;
int photoresistorPin = A0; // connection pin on arduino from sensor
int decValue = 0;
int analogValue = 0;
int delay_stepper = 1000;
Stepper myStepper(stepsPerRevolution, 6, 7);
bool daylight = true;
int steps;

void setup() { 
  pinMode(dir_pin, OUTPUT); 
  pinMode(step_pin, OUTPUT);
  pinMode(home_switch, INPUT_PULLUP);   
  pinMode(photoresistorPin, INPUT);
  myStepper.setSpeed(120);
  Serial.begin(9600);
}

void loop() {
  decValue = analogRead(photoresistorPin);
  x = map(decValue, 0, 1023, 0, 100);
  Serial.println(x);
  if ( x > 75 ) {
    daylight == true;
  }
  else
  daylight == false;
  
  if ((daylight == true) && (home_switch == LOW)){
    digitalWrite(dir_pin,HIGH);
  }
  if ((daylight == false) && (home_switch == HIGH)) {
    digitalWrite (dir_pin, LOW);
  }

  digitalWrite(step_pin,HIGH);
  delayMicroseconds(delay_stepper);   
  digitalWrite(step_pin,LOW); 
  delayMicroseconds(delay_stepper);
}

You have mixed up == and = here:

    daylight == true;

Hi,
Have you written your code in stages?
Written code JUST to read the phottransistor, got it working.
Written code JUST to control the stepper, got it working.

Have you at any stage got full control oft he stepper.

Can you post a copy of your circuit please?
What are you powering your project with?
What current is your stepper rated at?

x = map(decValue, 0, 1023, 0, 65000);

map uses int type variables, -32,768 to 32,767, so 65000 is going to cause a problem.

Tom..,. :slight_smile:

if ( x > 75 ) {
    daylight == true;
  }
  else
  daylight == false;

As others have said, you've mixed up == with = here.

But also my code had 2 thresholds for a particular reason. It is called hysteresis and ensures that if the light fluctuates a bit your system doesn't get "stuck in an open/close/open/close loop as the light levels vary". Instead, once brightness is above 75% it is daylight, but it must drop below 25% to change to night. Similarly in the reverse direction.

In order to avoid errors I would also highly recommend braces { } for every IF and ELSE code block.

 if ((daylight == true) && (home_switch == LOW)){
    digitalWrite(dir_pin,HIGH);
  }
  if ((daylight == false) && (home_switch == HIGH)) {
    digitalWrite (dir_pin, LOW);
  }

You only have one home switch. I don't think this is going to work. As soon as the motor start opening the home switch will change state to open.

If you have two home switches (open and closed) then it can work that way. Otherwise you need to count pulses as in my second example to decided when to stop opening. To close you can run until you detect the end stop.

Edit: More importantly "home_switch" is the name of the pin number variable, not the state of the switch. To detect the state of the switch you need to "digitalRead(home_switch)" to get the switch state.

 digitalWrite(step_pin,HIGH);
  delayMicroseconds(delay_stepper);   
  digitalWrite(step_pin,LOW);
  delayMicroseconds(delay_stepper);

This code executes every time through loop(). That's a mistake because the stepper will always be stepping in either one direction or the other. Note my code only steps in the OPEN direction if it detects that it is daylight AND we are not fully open. Similarly it only does a step in the CLOSE direction if it detects it is night AND we are not fully closed.

if ( x > 75 ) {
    daylight == true;
  }
  else
  daylight == false;

can be simplified todaylight = (x > 75);

wildbill:
You have mixed up == and = here:

    daylight == true;

Thanks for the heads up ^^

TomGeorge:
Hi,
Have you written your code in stages?
Written code JUST to read the phottransistor, got it working.
Written code JUST to control the stepper, got it working.

Have you at any stage got full control oft he stepper.

Can you post a copy of your circuit please?
What are you powering your project with?
What current is your stepper rated at?

x = map(decValue, 0, 1023, 0, 65000);

map uses int type variables, -32,768 to 32,767, so 65000 is going to cause a problem.

Tom..,. :slight_smile:

Hello,

I did the code for phototransistor, stepper motor I managed to make it spin but haven't managed so far to make it stop at the point I want it or after certain number of turns.
I will update my first comment with the diagram so please check it up so people in future can see it right away
Im powering it with 12V 2A led light charger
Stepper is rated for 12V 1.3A

pcbbc:

if ( x > 75 ) {

daylight == true;
  }
  else
  daylight == false;



As others have said, you've mixed up == with = here.

But also my code had 2 thresholds for a particular reason. It is called [hysteresis](https://en.wikipedia.org/wiki/Hysteresis) and ensures that if the light fluctuates a bit your system doesn't get "stuck in an open/close/open/close loop as the light levels vary". Instead, once brightness is above 75% it is daylight, but it must drop below 25% to change to night. Similarly in the reverse direction.

In order to avoid errors I would also highly recommend braces { } for every IF and ELSE code block.



if ((daylight == true) && (home_switch == LOW)){
    digitalWrite(dir_pin,HIGH);
  }
  if ((daylight == false) && (home_switch == HIGH)) {
    digitalWrite (dir_pin, LOW);
  }



You only have one home switch. I don't think this is going to work. As soon as the motor start opening the home switch will change state to open.

If you have two home switches (open and closed) then it can work that way. Otherwise you need to count pulses as in my second example to decided when to stop opening. To close you can run until you detect the end stop.

Edit: More importantly "home_switch" is the name of the pin number variable, **not** the state of the switch. To detect the state of the switch you need to "digitalRead(home_switch)" to get the switch state.



digitalWrite(step_pin,HIGH);
  delayMicroseconds(delay_stepper); 
  digitalWrite(step_pin,LOW);
  delayMicroseconds(delay_stepper);



This code executes every time through loop(). That's a mistake because the stepper will always be stepping in either one direction or the other. Note my code only steps in the OPEN direction if it detects that it is daylight AND we are not fully open. Similarly it only does a step in the CLOSE direction if it detects it is night AND we are not fully closed.

Thanks again for pointing out what I failed at, I will try to improve it as much as I can but I might need a day or two to try to figure it out and actually test it

TheMemberFormerlyKnownAsAWOL:

if ( x > 75 ) {

daylight == true;
  }
  else
  daylight == false;


can be simplified to`daylight = (x > 75); `

I assume any simplification is welcome, thanks !

I assume any simplification is welcome, thanks !

Yes, but that doesn’t have any hysteresis.

Hi,
If you update any code or diagrams its better to post them as new posts rather than go back and change an old post.
OPs new diagram;

Tom... :slight_smile:

Hi,
This is the pinout of your relay, how does it correlate to your diagram?
What is the relay meant to do?

Think a hand drawn circuit would be better.
Tom... :slight_smile:

TomGeorge:
Hi,
This is the pinout of your relay, how does it correlate to your diagram?
What is the relay meant to do?

Think a hand drawn circuit would be better.
Tom... :slight_smile:

Hi,
Thanks for uploading my picture to be more visible !

Relay was mainly used for purpose of stopping stepper from vibrating and really slowly turning once arduino is connected to PC (5V).

I am going to do the hand drawing and post it here in a while

Here is the drawn diagram, I am currently away from house so I don't really have any drawing tools to make it look more beautiful but I hope you can understand it

Hi,
Thanks for the circuit;
Can you explain what the circled parts of the relay are supposed to do?
As you have drawn them, if the relay coil is activated or not, the contacts do not change the circuit.
The only time the relay is activated is when you have your project powered up, it is deactivated when you disconnect the 12V supply.

Tom... :slight_smile:

TomGeorge:
Hi,
Thanks for the circuit;
Can you explain what the circled parts of the relay are supposed to do?
As you have drawn them, if the relay coil is activated or not, the contacts do not change the circuit.
The only time the relay is activated is when you have your project powered up, it is deactivated when you disconnect the 12V supply.

Tom... :slight_smile:

Hi,

Yes, when I'd want to change/upload/monitor through arduino without relay, motor would start to vibrate and slowly spin because driver would be automatically powered up and that would result in unnecessary movements. So to bypassing that I use relay to actually be able to operate arduino without having to unplug it everytime, since coil wouldn't be active as 12V source is not plugged in. By further going through coding and more deeper I think I can even get rid of the relay as long as I figure out how driver works properly and how to code it in order to not supply enough current/voltage.
As for the circled parts, driver would be given 5V only when 12V are plugged in otherwise driver/motor would be inactive

Hi,

As for the circled parts, driver would be given 5V only when 12V are plugged in otherwise driver/motor would be inactive

This does not happen in your circuit diagram.

I think this is what you have to do isolate the 12V supply from the 2009, when it is turned off.
But I can't see how it will solve your problem.

C is the common of each change over switch.
NC is the normally closed contact when the coil is deactivated.
NO is the normally open contact when the coil is deactivated and closed when the coil is activated.

Tom.... :slight_smile:

TomGeorge:
Hi,
This does not happen in your circuit diagram.

I think this is what you have to do isolate the 12V supply from the 2009, when it is turned off.
But I can't see how it will solve your problem.

C is the common of each change over switch.
NC is the normally closed contact when the coil is deactivated.
NO is the normally open contact when the coil is deactivated and closed when the coil is activated.

Tom.... :slight_smile:

Hello,

I can see what you mean and you're right I failed, not thinking enough or just doing it fast without checking out, but I will test what is the outcome with this kind of connection and going to let you know, thank you for pointing out where I made a mistake !. After more carefully and focused examination I was actually using wrong diagram of relay... Sorry for taking your time on such trivial thing, I'll make sure to ask better checked questions in future !

pcbbc:

if ( x > 75 ) {

daylight == true;
  }
  else
  daylight == false;



As others have said, you've mixed up == with = here.

But also my code had 2 thresholds for a particular reason. It is called [hysteresis](https://en.wikipedia.org/wiki/Hysteresis) and ensures that if the light fluctuates a bit your system doesn't get "stuck in an open/close/open/close loop as the light levels vary". Instead, once brightness is above 75% it is daylight, but it must drop below 25% to change to night. Similarly in the reverse direction.

In order to avoid errors I would also highly recommend braces { } for every IF and ELSE code block.



if ((daylight == true) && (home_switch == LOW)){
    digitalWrite(dir_pin,HIGH);
  }
  if ((daylight == false) && (home_switch == HIGH)) {
    digitalWrite (dir_pin, LOW);
  }



You only have one home switch. I don't think this is going to work. As soon as the motor start opening the home switch will change state to open.

If you have two home switches (open and closed) then it can work that way. Otherwise you need to count pulses as in my second example to decided when to stop opening. To close you can run until you detect the end stop.

Edit: More importantly "home_switch" is the name of the pin number variable, **not** the state of the switch. To detect the state of the switch you need to "digitalRead(home_switch)" to get the switch state.



digitalWrite(step_pin,HIGH);
  delayMicroseconds(delay_stepper); 
  digitalWrite(step_pin,LOW);
  delayMicroseconds(delay_stepper);



This code executes every time through loop(). That's a mistake because the stepper will always be stepping in either one direction or the other. Note my code only steps in the OPEN direction if it detects that it is daylight AND we are not fully open. Similarly it only does a step in the CLOSE direction if it detects it is night AND we are not fully closed.

Hello,

I've been playing with the code for a while and I came up with bunch of new lines, I must admit that hysteresis that I implemented is quite confusing me and I don't even know if its done correctly. Next I am getting a new type of error that I can't seem to get rid of and yes I do have only 1 switch so I would like to set a certain point to be a 0 to which motor will keep on coming back once closing up and there will be switch at the top of mechanism once it opens and reaches position it will activate the switch, at which point I can also read how many steps it took to reach that point and use that in code, I just need to explore how to do that cause so far haven't managed to find how to operate the motor through the driver I use. Hope you can help me out !.

EDIT: Also I have a question since hysteresis is using numbers from (0,1023) and since I mapped that value from (0,100), once I read serialprint does it have to be from analogRead or it can be from X I mapped up before that?

#include <Stepper.h>
//Defining pins
#define step_pin 6 // connected with step pin on driver
#define dir_pin 5 // connected with dir pin on driver
#define home_switch 3
uint16_t OutputLevel( uint16_t inputLevel ) {    
  const uint16_t margin = 5;   //  +/- 5
  const uint16_t numberOfLevelsOutput = 2; 
  const uint16_t endPointInput[ numberOfLevelsOutput + 1 ] = { 0, 35, 55} ;
  const uint16_t initialOutputLevel = 0 ;
  static uint16_t currentOutputLevel = initialOutputLevel ;
  uint16_t lb = endPointInput[ currentOutputLevel ] ;
  if ( currentOutputLevel > 0 ) lb -= margin  ;   
  uint16_t ub = endPointInput[ currentOutputLevel + 1 ] ;
  if ( currentOutputLevel < numberOfLevelsOutput ) ub +=  margin  ;  
  if ( inputLevel < lb || inputLevel > ub ) { 
    uint16_t i;
    for ( i = 0 ; i < numberOfLevelsOutput ; i++ ) {
      if ( inputLevel >= endPointInput[ i ] && inputLevel <= endPointInput[ i + 1 ] ) break ;
    }
    currentOutputLevel = i ;
  }
  return currentOutputLevel ;
}
const int stepsPerRevolution = 200;
const int maxReading = 55; // for opening
const int minReading = 25; // for closing
unsigned int x=100;
int photoresistorPin = A0; // connection pin on arduino from sensor
int decValue = 0;
int analogValue = 0;
int delay_stepper = 1000;
Stepper myStepper(stepsPerRevolution, 6, 7);
bool daylight = false;
int steps;

void setup() { 
  pinMode(dir_pin, OUTPUT); 
  pinMode(step_pin, OUTPUT);
  pinMode(home_switch, INPUT_PULLUP);   
  pinMode(photoresistorPin, INPUT);
  myStepper.setSpeed(120);
  digitalRead(home_switch);
  Serial.begin(9600);
}
  void light()
  {
    delay(500);
    while (OutputLevel == 2){
    daylight = true;  
    }
  }
  void dark(){
    delay(500);

    while (OutputLevel == 1){
      daylight = false;
    }
}

void loop() {
  decValue = analogRead(photoresistorPin);
  x = map(decValue, 0, 1023, 0, 100);
  Serial.print( decValue ) ;
  Serial.print("  " ) ;
  Serial.println(  OutputLevel( x ) ) ;
  delay ( 500 ) ;

  if ((daylight = true) && (digitalRead(home_switch)) = 0){
    digitalWrite (step_pin, HIGH);
    digitalWrite (dir_pin, HIGH);
  else if ((daylight = false) && (digitalRead(home_switch)) = 1) {
    digitalWrite (step_pin, LOW);
    digitalWrite (dir_pin, LOW);
  }
  }
  }

Error message:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"

sketch_jul28a:69:57: error: lvalue required as left operand of assignment

   if ((daylight = true) && (digitalRead(home_switch)) = 0){

                                                         ^

sketch_jul28a:73:63: error: lvalue required as left operand of assignment

   else if ((daylight = false) && (digitalRead(home_switch)) = 1) {

                                                               
exit status 1

lvalue required as left operand of assignment

== 0

Or better still

== LOW

if ((daylight = true)

Simplyif (daylight &&

TheMemberFormerlyKnownAsAWOL:
== 0

Or better still

== LOW

Yes, that solved the error thank you !