Creating your own servo control library

Article-series: Arduino - using_servos #6

We have created a class to control a servo. But if we want to use it in several projects, then for each we will need to copy the same code. Therefore, it makes sense to separate all the repetitive code into a separate library, which we will connect in the same way as the standard Arduino libraries

So, we go to the /libraries folder of our Arduino development environment, and we see 10-15 folders, each of which represents the standard Arduino library. Let's create a folder for our library here, for example ServoClass. Inside this folder we will create two files: ServoS.h, ServoS.cpp. Unfortunately, the Arduino IDE does not support editing files with a resolution other than .ino. Therefore, you will have to edit the library either in another development environment that supports C++ or in a regular text editor with syntax highlighting, for example AkelPad.

The first file, ServoS.h is a header file (from the word header file), the class itself, variables and functions will be described here. At the same time, there is only a list of variables and functions and their types, without the body of the functions themselves.

Let's copy our class ServoClass into the file ServoS.h, more precisely only the variables and function names:

/* Custom servo control library */

#ifndef ServoS // If the library has not yet been included

#define ServoS // Connect it

#include "Arduino.h" // Use the standard Arduino library

#include "Servo.h" // Use the standard servo control library

class ServoClass

{

public:

Servo serv; // Actually the servo itself, controlled by the standard

// servo library

int servPosition; // Current servo position, degrees

int posMax; // Maximum permissible limit of servo movement, degrees

int posMin; // Minimum permissible limit of servo movement, degrees

int posInit; // Initial position of the servo, degrees

// Variables that are responsible for movement

boolean move; // Should the servo currently move?

int movePosition; // Position the servo should take, degrees

float moveSpeed; // Speed at which the servo should move, rpm

int moveIncrement; // change in position over one time interval, degrees

int moveInterval; // Interval between movements to ensure speed, milliseconds

unsigned long lastTimeCheck; // Time of the last movement of the servo drive, in ms from the start of the program

ServoClass(); // Class constructor

void AttachServo(int pin); //Initialize the servo drive indicating only the output numbers for connection

void AttachServo(int pin, int minpos, int maxpos, int initpos); //Initialize the servo with minimum, maximum and home position

int PositionCheck(int movepos); // Check if the position falls within the specified interval

void MoveTo(int movepos); // Give a command to move the servo

void MoveTo(int movepos, float movespeed) ; // Give a command to move the servo indicating the speed

void Update(); //Movement processing

};

#endif

When creating a library, you may notice some features:

The file begins with the #ifndef ServoS directive, which checks whether this library has been included previously. If we have not connected it anywhere before, then the code located between #define ServoS and #endif will be added to the program

In addition, we define several functions with the same name but different arguments. This is due to the fact that when using libraries, calling a function with fewer than the defined number of arguments will result in an error. It will not be possible to set default argument values; more precisely, for each case you will need to describe a separate function. Therefore, we have two functions each: AttachServo and MoveTo

Now all that remains is to deal with the ServoS.cpp file. Here is the code for the functions described in the header file. In this case, we need to indicate which class the called functions belong to. Since our library uses the ServoClass class, all functions will relate to it. In the case of a constructor whose name matches the name of the class, it will look like ServoClass::ServoClass(), the remaining functions will look like ServoClass::FunctionName();

/* Custom servo control library */

#include "ServoS.h" // Include the header file

ServoClass::ServoClass() // Class constructor

{

posMin=0;

posMax=180;

posInit=0;

servPosition=0;

lastTimeCheck=millis();

}

void ServoClass::AttachServo (int pin) ////Initializing the servo drive indicating only the output numbers to connect

{

serv.attach(pin); // Connect the servo to the specified pin

posMin= 0; // Set the minimum position

posMax= 180; // Set the maximum position

posInit= 0; // Set the starting position

servPosition= posInit; // The servo position must match the home position

serv.write(servPosition); // Give the command to change position

}

void ServoClass::AttachServo (int pin, int minpos, int maxpos, int initpos) //Initialize the servo with minimum, maximum and home position

{

serv.attach(pin); // Connect the servo to the specified pin

posMin= minpos; // Set the minimum position

posMax= maxpos; // Set the maximum position

posInit= initpos; // Set the starting position

servPosition= posInit; // The servo position must match the home position

serv.write(servPosition); // Give the command to change position

}

int ServoClass::PositionCheck(int movepos) // Checking whether the position falls within the specified interval

{

int CheckedPos;

if (movepos<=posMin) // If a value greater than the maximum is specified

// movement limit

CheckedPos =posMin; // We will only move up to this limit

else

if (movepos>=posMax) // If a value less than the minimum is specified

//travel limit

CheckedPos =posMin; // We will only move up to this limit

else // In any other cases, we are within the permissible limits for movement

CheckedPos = movepos; // Just set the position where we should

return CheckedPos;

}

void ServoClass::MoveTo (int movepos) // If the speed is not specified, simply give a command to move the servo

{

movePosition = PositionCheck(movepos); // Check if we are within the permissible movement limits

serv.write(servPosition); // Give the command to change position

}

void ServoClass::MoveTo (int movepos, float movespeed) // If the speed is specified, we organize smooth movement

{

movePosition = PositionCheck(movepos); // Check if we are within the permissible movement limits

moveSpeed=movespeed; // Set the speed at which the servo should move

int Angle=abs(movePosition-servPosition); // How much should the servo move

// regardless of direction

if (movePosition >= servPosition) // Determine which direction from the current position we need to move

moveIncrement=1; // If forward, we will add one degree per time interval

else

moveIncrement=-1; // If back, then take away

float RotationSpeed=moveSpeed*360/60; // Convert the speed from revolutions per minute to degrees per second

moveInterval=(int)1000/RotationSpeed; // Calculate the interval between movements by one degree

move=true; // Give the command to start smooth movement

}

void ServoClass::Update () ////Movement processing

{

if (move) //If a command to move is given

{

if ((millis() - lastTimeCheck)>= moveInterval) // check how much time has passed since the last

//actions and compare with the interval we need.

//If more time has passed, perform the next action

{

servPosition+=moveIncrement; // Change the angle to the previously calculated value

serv.write(servPosition); // Send a command to the servo with a new rotation angle

lastTimeCheck= millis(); // Update the time counter so that the next time countdown starts from this moment

if (servPosition==movePosition) // If we have reached the desired position -

move=false; // stop movement

}

}

}

If the Arduino IDE was enabled when we created our library, then it will need to be closed and restarted again, since it collects data about available libraries during startup and will need to see our new library

Actually, we are done with creating the library, all that remains is to connect it to our program. To do this, simply replace the description of our class from previous example to "#include "ServoS.h"" Let's connect two servos and upload the sketch:

Scheme for connecting two servos to Arduino with rotation angle limitation and control via a user library

#include "Servo.h" // Include the library for working with the servo drive

#include "ServoS.h" // Include a custom library for working with the servo drive

ServoClass serv1;

ServoClass serv2;

void setup()

{

serv1.AttachServo(2); // The first servo is connected to the second pin

// Standard movement limits from 0 to 180 degrees

// Default home position is 0 degrees

serv2.AttachServo(3, 20, 160, 90); // The second servo is connected to the third pin

// Limits of movement from 20 to 160 degrees

// Starting position - 90 degrees

serv1.MoveTo(20); // Move the first servo to the 20-degree position

serv2.MoveTo(150, 0.5); // Move the second servo to the 150-degree position at 0.5 rpm

}

void loop()

{

serv1.Update(); // Process the movements of the first servo

serv2.Update(); // Process the movements of the second servo

}

The result of the program has not changed - the first servo will take the specified position immediately, and the second will rotate quite slowly (its initial position is 90 degrees, to move to the 150 degree position you need to turn 60 degrees. A speed of 0.5 revolutions per minute corresponds to 3 degrees per second, t This movement will take 20 seconds).

All that remains is to design our library for more convenient use. If you use the Arduino IDE, then the functions of standard libraries are highlighted in color, but for our library they are not. Therefore, we need to tell the program which functions need to be highlighted; to do this, we need to create a file keywords.txt in our library folder

Let's put information about the keywords that need to be highlighted there:

# Syntax highlighting for the ServoS library

ServoClass KEYWORD1

AttachServo KEYWORD2

PositionCheck KEYWORD2

MoveTo KEYWORD2

Update KEYWORD2

Words marked KEYWORD1 will be highlighted as a data type, KEYWORD2 – as functions. A tab sign is placed between a word and its type, and a line feed is placed between lines.

Let's restart the Arduino IDE again, now our class and its functions are highlighted in the appropriate color

Еще:

Подключаем сервопривод к Arduino (Arduino, использование сервоприводов #1)
Создаем класс для управления сервоприводом (Arduino, использование сервоприводов #3)
Программное ограничение перемещения сервопривода (Arduino, использование сервоприводов #4)