GMU:Functions and Classes (Arduino): Difference between revisions

From Medien Wiki
No edit summary
 
(27 intermediate revisions by the same user not shown)
Line 4: Line 4:


* clarity: the bigger the program gets the harder it is to keep the general overview
* clarity: the bigger the program gets the harder it is to keep the general overview
* decoupling: you only want to change a certain part of the program without influencing all the rest
* decoupling: you only want to change a certain part of the program without influencing all the rest of it
* recyclability: there are several similar parts in your robot for which you would like to reuse particular sections of your code
* recyclability: there are several similar parts in your robot for which you would like to reuse particular sections of your code




These problems reach back to the beginning of programming and their solution is an art and a science at the same time.
These problems reach back to the beginning of programming and their solution is an art and a science at the same time.<br>
It generally helps a lot to separate your program into single subunits that are relatively independent from each other.
It generally helps a lot to separate your program into single subunits that are relatively independent from each other.


Line 16: Line 16:
The [http://arduino.cc/de/Reference/FunctionDeclaration function] is an enormous useful tool that can help you structuring your code. Functions allow you to sum up several operations under the same command. This command can be called again and again without knowing about or duplicating the included code.  
The [http://arduino.cc/de/Reference/FunctionDeclaration function] is an enormous useful tool that can help you structuring your code. Functions allow you to sum up several operations under the same command. This command can be called again and again without knowing about or duplicating the included code.  


Here is an example for a function for setting the speed of a motor that is connected to an H-bridge:
Here is an example for a function that sets the speed of a motor which is connected to an H-bridge:




[[File:OOPARD1.jpg]]
[[File:OOPARD1.jpg]]
[[File:OOPARD2.jpg]]




Line 27: Line 25:




''setMotorSpeed(speed, leftForwardPin, leftReversePin, leftThrottlePin); // the pin numbers are saved in variables''
[[File:OOPARD2.jpg]]




This already saves us a lot of typing –
This already saves us a lot of typing –<br>
But one thing still seems quite laborious: we have to know the exact pin numbers every time we want to change the speed.
But one thing still seems quite laborious: we have to know the exact pin numbers every time when we want to change the speed.


Imagine a program in which similar function calls are distributed all over.  
Imagine a program in which similar function calls are distributed all over. <br>
In case of a hardware update you would have to find every single function call and change the parameters manually.  
In case of a hardware update you would have to find every single function call and change the parameters manually. <br>
This effort could surely be spent for more useful things..
This effort could surely be spent for more useful things..


It would be ideal to find a way of calling a certain function that only offers the most useful parameters (like setting the speed) and which handles technical details (switching pins on and off) internally.
It would be ideal to find a way of calling a certain function that only offers the most useful parameters (like setting the speed) and which handles technical details (switching pins on and off) internally.


==Possible solution: Data and code in one package „Classes“ and „Objects“==
<br>


C++ (and also Arduino) provides a specific feature that can solve our problem: Classes and Objects
==Possible Solution: Data and Code in One Package – "Classes" and "Objects"==


A Class predefines common qualities of a group of Objects.  
C++ (and also Arduino) provides a specific feature that can solve our problem: Classes and Objects.
It for instance determines that every motor has the possibility to exert a certain amount of throttle.  
 
A Class predefines common qualities of a group of Objects. <br>
It for instance determines that every motor has the possibility to exert a certain amount of throttle. <br>
The corresponding program could look like this:
The corresponding program could look like this:




''class Motor{
[[File:OOPARD3.jpg]]
public: // the following qualities and methods are visible from the outside.
void setThrottle(int newThrottle); // every motor has the possibility to exert trottle.
}''




Now the computer knows that there is a class called „Motor“.
Now the computer knows that there is a class called "Motor".<br>
This class (class) provides a function called „setThrottle“ that is called as an argument by using a number (int) and that does not return anything (void).
This class (class) provides a function called "setThrottle" that is called as an argument by using a number (int) and that does not return anything (void).




===Classes are Data-types===
===Classes are Data Types===


We can use our „Motor“ - class the same way we are using other data - types (int, long, float).
We can use our "Motor" - class the same way we are using other data - types (int, long, float).<br>
The following lines use that quality in order to implement two motors:
The following lines use that quality in order to implement two motors:
<br>
<br>


[[File:OOPARD4.jpg]]


''Motor leftMotor; //  declare an object of the type „Motor“ called „leftMotor“
<br>
Motor rightMotor; //  declare another object of the type „Motor“ called „rightMotor“
<br>
''
 
 


===Calling inner functions of a class (Methods)===
===Calling inner functions of a class (Methods)===


Imagine we want to drive the left motor with full throttle whereas the right motor should stop completely.  
Imagine we want to drive the left motor with full throttle whereas the right motor should stop completely. <br>
This can be expressed as follows:
This can be expressed as follows:




''// the objetcs name „leftMotor“ and the herein implemented function „setThrottle“ are separated by a dot.
[[File:OOPARD5.jpg]]
leftMotor.setThrottle(255);
rightMotor.setThrottle(0);
''




A positive side effect: your program gains readability by picking distinct names for your Objects and Methods.
A positive side effect: your program gains readability by picking distinct names for your Objects and Methods.


<br>


===Classes can contain other variables that can only be accessed "internally"===


===Classes can contain other variables that can only be accessed „internally“===


How do the Objects "leftMotor" and "rightMotor" know which pins they want to switch on and off?


How do the Objects „leftMotor“ and „rightMotor“ know which pins they want to switch on and off?
Until now our "Motor" class is quite abstract since it does not contain this information. <br>
 
A class that should conduct practical actions needs further variables (concrete pin numbers) and lines of code that describe what to do exactly.<br>
Until now our „Motor“ class is quite abstract since it does not contain this information.  
A class that should conduct practical actions needs further variables (concrete pin numbers) and lines of code that describe what to do exactly.
We can simply include both things in the class definition:
We can simply include both things in the class definition:




''
[[File:OOPARD6.jpg]]
class MotoMamaMotor {
...
private: // the following definitions are only of „internal use“ for the class itself     
int forwardPin; //  c
int reversePin;
int throttlePin;
...
};
''
 
 
How do we include the pin numbers into the Object if they are not visible from the outside?
We simply write a „setup“ Function for the class:
 
 
''
class MotoMamaMotor {
private:
...
public: //  we want the setup-function to be accessible from the outside.
void setup (int newForwardPin, int newReversePin, int newThrottlePin){
// we remember the pins for future use         
forwardPin=newForwardPin;
reversePin=newReversePin;
throttlePin=newThrottlePin;
// and at the same time we initialize the outputs !
digitalWrite(throttlePin,LOW); //  so that the motors don’t spin directly from the beginning ..
pinMode(forwardPin,OUTPUT);
pinMode(reversePin,OUTPUT);
pinMode(throttlePin,OUTPUT);
}
...
};
''
 
 
 
==A complete example ==
 
 
In order to construct a complete example we only have to include the „speed“-Function (see description above):




''
How do we include the pin numbers into the Object if they are not visible from the outside?<br>
// Defining a class for motor control
We simply write a "setup" Function for the class:


class MotoMamaMotor {


private: // the following definitions are only of „internal use“ for the class itself
[[File:OOPARD7.jpg]]
int forwardPin; //Every MotoMamaMotor type Object has its own forwardPin
int reversePin;
int throttlePin;


public: // the following qualities and methods are visible from the outside.
<br>
//  This setup-Function has to be called before using the motor control
<br>
void setup(int newForwardPin, int newReversePin, int newThrottlePin){
// we remember the pins for future use         
forwardPin=newForwardPin;
reversePin=newReversePin;
throttlePin=newThrottlePin;
// and at the same time we initialize the outputs !
digitalWrite(throttlePin,LOW); //  so that the motors don’t spin directly from the beginning ..
pinMode(forwardPin,OUTPUT);
pinMode(reversePin,OUTPUT);
pinMode(throttlePin,OUTPUT);
}


// this Function allows to control the motor speed
==A Complete Example ==
void setThrottle (int newThrottle){
if (newThrottle>0){ // should it spin forwards or backwards?
// spin forwards
digitalWrite(reversePin,LOW);
digitalWrite(forwardPin,HIGH);
}else{
// spin backwards
digitalWrite(forwardPin,LOW);
digitalWrite(reversePin,HIGH);
}
// adjust the speed:
analogWrite(throttlePin, newThrottle);
}
};


// create two separate MotoMamaMotor type Objects (leftMotor, rightMotor). They can be used as normal variables.
MotoMamaMotor leftMotor;
MotoMamaMotor rightMotor;


void setup(){  // this is our „main“ setup Function
In order to construct a complete example we only have to include the "speed"-Function (see description above):
leftMotor.setup(3,4,5);  // assign the pin numbers for each motor in the setup Function: setup(int newForwardPin, int newReversePin, int newThrottlePin)
rightMotor.setup(6,7,8);
};


void loop(){  // this is our „main“ loop Function where concrete actions are executed. For example:
// Start backwards, slow down and accelerate forwards
for (int i =-255, i<=255;i++){
leftMotor.setThrottle(i);
rightMotor.setThrottle(i);
};
// Start forwards, slow down and accelerate backwards
for (int i =255, i>=-255;i--){
leftMotor.setThrottle(i);
rightMotor.setThrottle(i);
};
};
''


[[File:OOPARD8.jpg]]


<br>
<br>


==Organizing classes in separate files==
==Organizing Classes in Separate Files==


We can improve our program structure by putting classes in separate files.


1)
We can improve our program structure by putting classes in separate files:
Click on the arrow in the right corner in order to add a new file.
Select „new Tab“.


----BILD----
1. <br>
Click on the arrow in the right corner in order to add a new file.<br>
Select "new Tab".


2)
Enter a filename at the bottom of the window.
It must end with .h !
In our case I suggest the name motorControl.h.


3)
[[File:NewTabARDU.jpg]]
Enter the first line:
<br>
2.<br>
Enter a filename at the bottom of the window. <br>
It must end with ".h" – In our case it could be "motorControl.h".


3.<br>
The first line of your code should be:


''
'#include „Arduino.h“'
#include „Arduino.h“
''


 
This line 'links' the file to the Arduino–specific features.<br>
This line „links“ the file to the Arduino-specific features.
Now we can include the code of our class.
Now we can include the code of our class.


4)
4.<br>
Go back to your main file.
Go back to your main file.<br>
Now you have to „link“ the new file to your main file in order to use the features of our class.
Now you have to "link" the new file to your main file in order to use the features of our class.<br>
Include the following line in the top of your main file
Include the following line in the top of your main file


 
'#include "MotorControl.h“'
''
#include „MotorControl.h“
''
 


and write the rest of your program as usual.
and write the rest of your program as usual.
<br>
<br>


==More Information==


Classes can build up on each other ("inheritance").


==More details on the concept==
In the beginning we promised that it is possible to replace different motor drivers without changing the rest of the program.<br>
 
Classes can indeed include other Objects in the form of "[https://en.wikipedia.org/wiki/Member_variable member variables]".
Classes can build up on each other (inheritance)


In the beginning we promised that it is possible to replace different motor drivers without changing the rest of the program.
C++ allows class declarations and the code for included Functions to be be placed in different files. <br>
Classes can indeed include other Objects in the form of „member variables“.
If you want to know more about that you can read this article about creating libraries in Arduino: <br>[http://arduino.cc/en/Hacking/LibraryTutorial http://arduino.cc/en/Hacking/LibraryTutorial ]


C++ allows class declarations and the code for included Functions to be be placed in different files.
<br>
If you want to know more about that you can read this article about creating libraries in Arduino: [http://arduino.cc/en/Hacking/LibraryTutorial http://arduino.cc/en/Hacking/LibraryTutorial ]
<br>
<br>

Latest revision as of 14:02, 28 March 2017

Motivation

Soon after starting to write the program for your robot you will encounter some typical problems:

  • clarity: the bigger the program gets the harder it is to keep the general overview
  • decoupling: you only want to change a certain part of the program without influencing all the rest of it
  • recyclability: there are several similar parts in your robot for which you would like to reuse particular sections of your code


These problems reach back to the beginning of programming and their solution is an art and a science at the same time.
It generally helps a lot to separate your program into single subunits that are relatively independent from each other.


Example: Controlling Motors

The function is an enormous useful tool that can help you structuring your code. Functions allow you to sum up several operations under the same command. This command can be called again and again without knowing about or duplicating the included code.

Here is an example for a function that sets the speed of a motor which is connected to an H-bridge:


OOPARD1.jpg


Now (and for every prospective motor movement) we only need to write one single line in order to for instance setting the left wheels speed:


OOPARD2.jpg


This already saves us a lot of typing –
But one thing still seems quite laborious: we have to know the exact pin numbers every time when we want to change the speed.

Imagine a program in which similar function calls are distributed all over.
In case of a hardware update you would have to find every single function call and change the parameters manually.
This effort could surely be spent for more useful things..

It would be ideal to find a way of calling a certain function that only offers the most useful parameters (like setting the speed) and which handles technical details (switching pins on and off) internally.


Possible Solution: Data and Code in One Package – "Classes" and "Objects"

C++ (and also Arduino) provides a specific feature that can solve our problem: Classes and Objects.

A Class predefines common qualities of a group of Objects.
It for instance determines that every motor has the possibility to exert a certain amount of throttle.
The corresponding program could look like this:


OOPARD3.jpg


Now the computer knows that there is a class called "Motor".
This class (class) provides a function called "setThrottle" that is called as an argument by using a number (int) and that does not return anything (void).


Classes are Data Types

We can use our "Motor" - class the same way we are using other data - types (int, long, float).
The following lines use that quality in order to implement two motors:

OOPARD4.jpg



Calling inner functions of a class (Methods)

Imagine we want to drive the left motor with full throttle whereas the right motor should stop completely.
This can be expressed as follows:


OOPARD5.jpg


A positive side effect: your program gains readability by picking distinct names for your Objects and Methods.


Classes can contain other variables that can only be accessed "internally"

How do the Objects "leftMotor" and "rightMotor" know which pins they want to switch on and off?

Until now our "Motor" class is quite abstract since it does not contain this information.
A class that should conduct practical actions needs further variables (concrete pin numbers) and lines of code that describe what to do exactly.
We can simply include both things in the class definition:


OOPARD6.jpg


How do we include the pin numbers into the Object if they are not visible from the outside?
We simply write a "setup" Function for the class:


OOPARD7.jpg



A Complete Example

In order to construct a complete example we only have to include the "speed"-Function (see description above):


OOPARD8.jpg



Organizing Classes in Separate Files

We can improve our program structure by putting classes in separate files:

1.
Click on the arrow in the right corner in order to add a new file.
Select "new Tab".


NewTabARDU.jpg
2.
Enter a filename at the bottom of the window.
It must end with ".h" – In our case it could be "motorControl.h".

3.
The first line of your code should be:

'#include „Arduino.h“'

This line 'links' the file to the Arduino–specific features.
Now we can include the code of our class.

4.
Go back to your main file.
Now you have to "link" the new file to your main file in order to use the features of our class.
Include the following line in the top of your main file

'#include "MotorControl.h“'

and write the rest of your program as usual.

More Information

Classes can build up on each other ("inheritance").

In the beginning we promised that it is possible to replace different motor drivers without changing the rest of the program.
Classes can indeed include other Objects in the form of "member variables".

C++ allows class declarations and the code for included Functions to be be placed in different files.
If you want to know more about that you can read this article about creating libraries in Arduino:
http://arduino.cc/en/Hacking/LibraryTutorial