[SOLVED] Help with logic

Hello

I am making a model that will have an arduino mega 2560 R3 controlling 2 stepper motors(with easy drivers) 4 servo motors and 1 solenoid(with a tip122 transistor, diode and secondary power source) and 2 LED 4 digit displays

the programming aim is to have 2 separate cycles running at the same time.

the first cycle includes one stepper 2 servos and the solenoid and second cycle includes a stepper and 2 servos

the model is of a mine shaft
The steppers control the location of the skip(the elevator car) in the shaft
the servos move gates that control the flow of ore(plastic beads)
2 servos control the gate that loads the skip(one for each cycle)
2 servos control the gate that is on the storage area(one for each cycle)
the skips dump in 2 different ways
the first is pushed open with the solenoid (simulating a dump using a hydraulic cylinder)
the second is moved slowly through a set of guides(simulating the use of scroll plates to dump the skip)

the second method of dumping take a little longer than the first method
so one cycle will 'out perform' the other

the number of cycles each side of the model completes is stored and displayed on the 4 digit display and updates after each cycle

for starters i want to have the whole model run by pressing a button to start both cycles at the same time. and have another button to stop both and reset the position of the skips and each LED display. But i aim to have it controlled by a computer and have a graph that outputs the real time speed of each skip as it runs through the cycle. also the number of cycles completed will be displayed on this screen aswell. but making a GUI can come after the simple version works properly.

I have never used an arduino before and have been reading the forums for 2 weeks figuring out how to control all my devices.

I have attached my first draft of my code. I am unsure what is supposed to be before and what is in the startup . It is just a draft of the timing for each process. and a lot of the proper brackets are missing like brackets in my if statements and semicolons everywhere.

I just want to make sure i understand and have adapted the blinkwithoutdelay properly before i move on and put all the right grammar libraries etc. into the code.

I havent actually got my arduino and parts in yet so i dont have definite numbers for what pins control what. Again just want to make sure im on the right track.

Thanks in advance

Matt

Edit: In the code I put Fastmove and Slowmove and said that they were times. In fact they should be a number of steps. fast move is the number of steps it takes to move the skip from the bottom of the scroll plates to the loading position. and slow move is the number of steps it takes to move the skip from the bottom of the scroll plate to the top of the scroll plate.

rough Code .txt (4.36 KB)

I wouldn't do it like that. Instead of just doing everything based solely on time, I suggest you implement a finite state machine for each independent thing you want to control. The state machine will keep track of the current state of that thing and determine when some action is needed based on passing time or other external triggers. Robin2 posted an example sketch a little while ago which demonstrated how to implement a finite state machine that included time-based activities.

My demo sketch is in the first post of this Thread.

Breaking the task into several separate short functions with meaningful names will make the logic of your system easy to follow withouth getting lost in the details.

The connection between the functions should be the variables that record the state of things.

Elaped time (as measured by the millis() function can be used to determine when some of the states need to change.

...R

You might find this video useful.

I actually used your post Robin2 initially to help me understand the blinkwithoutdelay. that is why I came up with having a state function to run the each cycle.

How easy it it to pass variable into functions? if i am to split up the main function further with say a movemotor function can i make the function so i call it like movemotor(on pin 4,clockwise, 31 steps, at 20rpm) and then call later movemotor(on pin 4, counterclockwise, 12 steps, at 5 rpm). I know it can be done in C++ but the arduino language is not exactly the same so im unsure. I will try to find a thread on arduino functions.

How would i incorporate multiple states into the main code instead of a 'is the program 1 running y/n' state. If were to have the loop function call a generic movemotor(pin#,dir,step,rpm) then a generic servomove(pin#,angle,rpm) or solenoid(on/off) [as there is only 1 solenoid]. Definitely it would simplify the code a lot and make debugging a lot easier. I'm just not quite sure how to add all the states into it then so that say the servo wont start moving until the motor has moved the correct distance. would i just make these states time based instead of having the time component in the if statements? So all the state intervals could be defined before the startup and then all i would have to do is reference the states in if statements when performing actions.

what would be the best way to update the states? motor 2 has 4 different motions it takes(2 directions and 2 speeds) a motor2(moving/not moving) state would be impossible to set up with a specific time. Would i make this into 4 states? and if i did how would i check the states through the program. depending on where it is the the cycle is would be checking different states so the servo function would have to know to check 4 different states in order to know if it should run or not. could i pass the state into the function? so when i call the servo function it would call it with the correct state and then inside the function it decided whether it is time to run or not. but wouldn't this potentially skip that step if it was not time to run it? it would see the state is false and not run then move on, rather than wait for the state to become true.

Is there a chance the arduino might skip a line say the motor is moving and it take 10 seconds to finish the move but the arduino sees the next line in .5 seconds and then says i cant open the servo because the motor isn't in the right position, ill go to the next line. so when the motor is finished moving the arduino has gone past what the next line of code should be. and starts doing something that should happen later.

I think if you use the stepper library the code waits for the motor to finish the move before it moves on but I'm not sure if this wait would affect the second cycle. if motor 1 is moving then the rest of cycle 1 should be paused until it finishes the move but cycle 2 should remain unaffected. how would i program the loop to call the generic functions like that?

And Jimbo i cant get that video you linked to work on the computer im on right now. i will definitely check it out this evening though.

Matt

I know it can be done in C++ but the arduino language is not exactly the same

What makes you think that it is different when it comes to such basics as passing variables to functions ?

In fact, if you thought about it for a split second you would know that it works otherwise the Arduino specific functions such as pinMode(), digitalWrite() and dozens of others would not work.

I'm just not quite sure how to add all the states into it then so that say the servo wont start moving until the motor has moved the correct distance.

Do some research on Finite State Machines.

At any one time the program is in one of many states doing whatever is needed in that state such as running a motor for a fixed time or until a limit switch is reached. Inputs and/or time passing cause the program to move to another state. A convenient way to do this is to use the switch/case construct with the switch based on the current state. What you must not do is to write code that blocks operation of the Arduino such as the delay() function. Timing is best done using the millis() function. Note the start time of a timed state (millis()) then each time through loop() check if it is time to end the current activity and move to a new state.

If you have more that one set of independent activities then you can have two FSMs running at the same time.

omgnames:
How easy it it to pass variable into functions? if i am to split up the main function further with say a movemotor function can i make the function so i call it like movemotor(on pin 4,clockwise, 31 steps, at 20rpm) and then call later movemotor(on pin 4, counterclockwise, 12 steps, at 5 rpm). I know it can be done in C++ but the arduino language is not exactly the same so im unsure. I will try to find a thread on arduino functions.

Arduino code is standard C/C++. You could do moveMotor(4, 'c', 31, 20);

Another option which makes sense in a small system like an Arduino is to use global variables rather than passing parameters.

I like to use global variables for values that represent the state of my system. I also think my code is easier to follow if my moveMotor() function picks up its own data from global variables as far as possible. It avoids the need for the code that calls the function to have complex logic about motor movements. For example, if there are three motors the moveMotor() function could iterate through an array to get the data for each motor.

...R

I know it can be done in C++ but the arduino language is not exactly the same

What makes you think that it is different when it comes to such basics as passing variables to functions ?

In C++ there is cin and cout that is not there in arduino code. i figured there may be some other minor differences. Never programmed an arduino so i was unsure. I looked up a function tutorial so im good with functions now. They seem to be exactly the same as what i remember from C++

Originally my code was going to be based on a the milis function. one cycle would start and when it did the milis would be recorded in a new variable. the next steps in the cycle would happen at a time when the current time is equal to the start time plus a value. the value being the time it took for the previous action or actions to be completed. when the cycle ended and then started again the start time of the cycle is updated and the time values that i would be adding to the start time would all be calculated beforehand as global constants. and each cycle had its own start time that it would be checking

Isn't that like using states? but instead of having when in state1 do X and state1 happens when Y but when in state 2 do A and state 2 happens when B. I just have when Y happens do X and when B happens do A. I was just skipping the definition of the specific states. or do i not understand states correctly?

I definitely see that naming the states and having the code switch between state 1 to 2 to 3 to 1 again makes the code easier to read. just need to clarify if i was doing a roundabout method of the same thing. I actually have a knack for finding a really complicated ways to do something before i discover the simple method. When i first learned C++ in school i would pick 3 letters and derive my variables from different combinations of them for short programs. so i would have variables names ert, etr, rte, ret, tre, ter in a program (id use another set if i needed more). I was basically too lazy to write out say coincounter or cardvalue for variable names. Horrible to read i know(i bet my teacher secretly hated me) but the programs would work and if the program works why debug it :stuck_out_tongue:

Matt

Watched the video jimbo posted it helped a lot. I think I understand states a bit more now. need to do some thinking to figure out how to use them effectively and how to call them with so many things that have to update.

Is there a way i could have a current position variable? if tell the stepper to move say 20 steps clockwise from 0 and it takes say 5 seconds to complete is there a way to check at what step it is at part way through the move? then i could base the states of the servos and solenoid on the position of the motor and if the motor state if on or off. Or would i have to derive a position equation based on the speed of the motor, its last position, rotation direction and time.

Matt

/* program to run 2 cyclyes simutainiously. 
one cycle is faster than the other so the LCD is supposed to tick up faster as it runs.

process for 1 elevator. 
take a load from the load area to the dump area 
dump load and go back to load area. 
elevator dumps into a storage area which in turn dumps into the loading area
the speed of the elevator is the only difference between cycles
one has to slow down as it approaches the dump area
approximate time difference between cycles could be as much as 30 seconds
when hcycle gets to 9999 scycle goes to 0 and hcycle is set to the difference between the cycles.
when the difference between the cycles is 9999 both cycles reset to 0
*/



//Global variables

long 	currentmilis;		// the time when the loop iterates
long	Hydralicstart;		//the last time the hydralic cycle started
long	Scrollstart;
long	Hcycle			//the time it take to complete one hydralic cycle
long	Scycle = 
int	Falltime=1000; 		//1 second
int	MaxS =	6000		//6000steps per minute(200steps per revolution- 30 rpm)
int	CreepS = MaxS* 0.25	//creep speed is 1/4 of max speed 
int	Hnum = 0		//# of hydralic cycles completed sice
int	Snum = 0		//# of scroll cycles completed
int 	loaddeg =  ;		//degres the loading servos need to turn
int	storedeg = ;		//degrees the storage servos need to turn




//Define pins (still no hardware in)
	output to motor 1 and 2(1=hydralic 2=scroll)
	outpus to solenoid 1  and servo 2-5(1=hydralic dump,2=hydralic storage,3=hydralic load,4=scroll storage,5=scroll load)
	output to led screen 1 and 2(1=hydralic display, 2=scroll display)
	input from start and reset bottons
//--------------------------------------------------------------------------------//
void startup()
{

}

//--------------------------------------------------------------------------------//
void loop()
{

currentmilis = milis();

if (start = High)			//checks to see if the button is on
	{		
	HydralicCycle;	
	ScrollCycle;

	if (Hnum = 9999)	//if the lcd is at 9999 subtract Snum from Hnum and then set Snum to 0
		{		
		Hnum=Hnum-Snum;
		Snum=0;
		}
	if (Hnum-Snum=9999)	//if the diference between the two cycles is 9999 set both to 0
		{	
		Hnum=0;
		Snum=0;
		}
	}

If (reset = high)
	{
	Hnum=0;
	Snum=0;
	//move both skips to dump position
	//close all gates
	}

}

//--------------------------------------------------------------------------------//
Void ScrollCycle() 
{

int faststeps;			//number of steps to take when moving fast
int slowsteps;			//number of steps to take when moving slow 
int Slowmove = slowstep/CreepS;	//time in milis to complete the movement
int fastmove = faststep/MaxS;	//time in milis to complete the movement

if (currenttime >= Scrollstart + Scycle)	//if it has been enough time to complete a cycle since the last cycle. start a cycle
	{
 	Scrollstart = currenttime;		//the start of the cycle is recorded.
	MoveMotor(2,D,slowsteps,CreepS)		// bring skip to below scrolls 
	}

if (currenttime >= Scrollstart + slowmove)
	{ 
	MoveMotor(2,D,faststeps,MaxS)		// bring skip to shaft bottom
	}

if (currenttime >= Scrollstart + slowmove + fastmove)  	//if skip has reached shaft bottom
	{ 
	Sevocontrol(5,open,loaddeg)		//load it
	}

if (currenttime >= Scrollstart + slowmove + fastmove + falltime) // after it loads
	{ 
	Sevocontrol(5,close,loaddeg)		//close loading gate
	MoveMotor(2,U,faststeps,MaxS)		// max speed to just below scrolls
	Sevocontrol(4,open,storedeg)		//open the storage gate
	}	

if (currenttime >= Scrollstart + slowmove + fastmove + 2*falltime) 	//while skip movin to top 
	{
	Sevocontrol(4,close,storedeg)		//close the storage gate
	}

if (currenttime >= Scrollstart + slowmove + 2*fastmove + falltime)	//what skip reached scrolls. fast move >> falltime
	{	
	MoveMotor(2,U,slowsteps,CreepS)		// skip creeps through scrolls
	}

if (currenttime >= Scrollstart + 2*slowmove + 2*fastmove + falltime)
	{
	Snum++
	Scrolldisplay;
	}
}


//--------------------------------------------------------------------------------//
Void HydralicCycle()
{
movesteps =			//number of steps to moce from top to bottom
movetime = 			//time in milis to complete the movment


if (currenttime >= Hydralicstart + Hcycle)	//if it has been enough time to complete a cycle since the last cycle. start a cycle
	{
 	Hydralicstart = currenttime;		//the start of the cycle is recorded.
	MoveMotor(1,D,movesteps,MaxS)		// bring skip to shaft bottom
	}

if (currenttime >= Hydralicstart + movetime)
	{						//after the skip has finished moving
	Sevocontrol(3,open,loaddeg)			//rotate servo 3 to load the skip
	}

if (currenttime >= Hydralicstart + movetime + falltime)
	{						//after the load has fallen in
	Sevocontrol(3,close,loaddeg)		
	MoveMotor(1,U,movesteps,MaxS) 			// order skip to top position	
	Sevocontrol(2,open,storedeg) 			// While skip onroute. storage dumps into loading area
	}
					 
if (currenttime >= Hydralicstart + movetime + 2*falltime)
	{ 						//after load has fallen out of storage
	Sevocontrol(2,close,storedeg)
	}

if (currenttime >= Hydralicstart + 2*movetime + falltime)
	{						//after skip moves to the dump position
	solenoidtoggle;					//toggle solenoid state( on)
}

if (currenttime >= Hydralicstart + 2*movetime + 2*falltime)
	{						//after the skip dumps
	solenoidtoggle;
	Hnum++
	Hydralicdisplay;
	}
}

//--------------------------------------------------------------------------------//
void MoveMotor(motor#,up or down,#ofSteps,Max or creep)
{
//code to turn the correct motor by the correct amount at the correct time
}

//--------------------------------------------------------------------------------//
void Sevocontrol(Servo#, Open or closed, degrees)
{
//code to open or close the correct sevo
}

//--------------------------------------------------------------------------------//
void solenoidtoggle()
{
If (solenoidstate = high)		//if the solenoid is on, turn it off
	{
	solenoidstate = low
	}

else				//else if it is off, turn it on
	{
	solenoidstate = high
	}
}

//--------------------------------------------------------------------------------//
void Scrolldisplay()
{
//uses the global Snum and prints it to the LED screen 
}
//--------------------------------------------------------------------------------//
void Hydralicdisplay()
{
//uses the global Hnum and prints it to the LED screen 
}

This is my code now. I think this should work in terms of my states.
Haven't put in the parts that send output to the motors or servos etc.

Still trying to figure out the LED screen and which method to use when talking to it.

And still don't have the parts yet so pin numbers still are up in the air. Hopeing when i do get them in I will have a program that is ready to test

Tried to add all the correct grammar in the code. I know I'm missing semicolons and stuff. It's a lot better than my first draft

Matt

Edit: Attached the notepad version if that is easier to look at

CodeVersion2.txt (6.34 KB)

You have a great many faults in your program. These few caught my eye ...

There is no setup() function

You have millis() spelled incorrectly

Your function calls eg. hydralicCycle; should be hydralicCycle(); (and it is hydraulic - but the compiler won't care)

You Notepad file is inconvenient as it has too much whitespace. Why not just upload the .ino file?

...R

i had meant "startup" to be "setup" oops

and yes my spelling is really bad, notepad has no spell check :stuck_out_tongue:

going to assume .ino is the file type that the arduino program makes. i had made this in notepad . compilers are annoying for roughing out code IMO. because it complains at you when you miss a semicolon or a //. i will be switching over to the arduino program now that im further into coding.

Started adding all the set up code and stuff just leaving the pin numbers blank for now.

Not sure how much white space is too much white space . i though proper spacing was good so things dont get crowded. especially when you get other people to help with your code. Im trying to make it neat and include lots of comments to make the editing easier.

Matt

When I loaded your notepad file there was a blank line between every line - real PITA.

White space between logical sections is very helpful.

I don't know what text editors on windows can be used for program editing and will highlight keywords, matching brackets etc. When you find one you can use it instead of the Arduino editor. Just check the external editor button in the Arduno prferences. The rest of the IDE functions as normal. When you click verify or upload it just takes the latest version of the file saved by your editor.

Complaints about missing semicolons etc are a good thing. If you aren't careful about that stuff you get tons of strange compiler errors that may confuse you into looking for a real problem.

It's a good idea to compile (verify) your code frequently (perhaps every 10 lines or so) as that helps you to catch silly errors early. Even better is to run your code frequenctly so you know that it actually does what you want before the problem gets lost in the spaghetti. (But I know you wouldn't write spaghetti code - you will have everything in its own function)

...R

Is there a way i could have a current position variable? if tell the stepper to move say 20 steps clockwise from 0 and it takes say 5 seconds to complete is there a way to check at what step it is at part way through the move?

Not unless you have some form of feedback from the motor such as a rotary encoder. What you could do as a compromise is to move the motor one step at a time instead of 20 then you would at least know which individual step it was executing at any point in the program.

I switched it over to the arduino program and added all the functions and pin definitions except for the two LED screens and actually assigning the pins values. had a whole bunch of errors for a while and worked them all out. ordering the parts today so depending on shipping i can start testing in a week or two.

Not sure if I'm missing commands in some of my functions or if the order I do things in is the best way to do them.
eg, in the servocontrol section I pass in what servo to use(number from 2-5) and I had my servo objects as:

servo2, servo3, servo4, servo5

So when it passed the 2 into the function and it became variable " a ", I tried to call " servo(a).write(); "
So a = 2 therefore is uses servo2 but the compiler saw servo (without a number) and that was undefined so I got errors
Ended up putting in a bunch of if statements.
It looks like this now

void Servocontrol(int a,char b,int c)//(Servo#, Open or closed, degrees)
{

if(b='O')	//if the servo wants to open rotate negative degrees. if it wants to close rotate positve degrees
	{
	c=!c;
	}
if (a=2){
        servo2.write(c);		//code to open or close the correct sevo
        }
if (a=3){
        servo3.write(c);		//code to open or close the correct sevo
        }
if (a=4){
        servo4.write(c);		//code to open or close the correct sevo
        }
if (a=5){
        servo5.write(c);		//code to open or close the correct sevo
        }
}

I will attach the full code as an .ino as well.

Matt

Edit: UKheliBob I ended up using the accelstepper library in which you have to set a position variable. i think i programmed it in a way that will work without having to check where it is.

code_v3.ino (7.89 KB)

Your code would be so much easier if you use arrays for multiple items. For example all the servos can be dealt with by one line of code

void Servocontrol(int a, int c)//(Servo#, degrees)
{
   servo[a].write(c);
}

...R

Robin2:
Your code would be so much easier if you use arrays for multiple items. For example all the servos can be dealt with by one line of code

void Servocontrol(int a, int c)//(Servo#, degrees)

{
  servo[a].write(c);
}




...R

How do I declare the servos at the top when using an array though? "servo2" is set as a servo object that I can control. If I try to change it to "servo[a].write(c);" it ignores the brackets and sees "servo" which isnt declared as a servo object and gives me an error.

Matt

Servo myServo[3]; creates an array of three servo objects called myServo[0], myServo[1] and myServo[2]

It's exactly the same as creating an array of any other objects.

...R

Thank you Robin2. I've updated it to arrays now.

The way i was calling the if statements in the cycle functions would of kept running the same if's over and over. I reversed the stack of if's and switched all but the first to if else. now only one if can run each time it goes through the loop instead of potentially all of them depending on the time.

Also the run(); function in accelstepper only moves the motor one step, you have to keep calling it. when i changed the code so only one if could run in a loop, the motor would have not necessarily made it all the way to its position (not that it would have made it before). now in the cycle function I set the destination and speed of the motor. The motor is called to run in the main loop.

Figured out what speeds and times I will be using. Also switched a bunch of variables over to constants (i think that is better memory wise?).
Made a rough wiring guide to help me hook it up when the parts get here.
Added the code for controlling the 4 digit LED displays. basically copied the code from an example.
Also coded the reset button in its entirety now.

I think this should work how I want it to. Now I want to figure out how to make a GUI for the arduino so I can run the program from there and maybe add more complex controls like adjusting the speed or acceleration.

I will likely make another post just about the GUI in a couple days after some research( Or when my parts come in and it doesn't work right haha)

Thanks for all the help Robin2 and UKHeliBob.

Matt

code_v4.ino (10.1 KB)

Thanks for the feedback.

...R