Creating Libraries from sketches?

Hi,
As someone new to programming, I've hit an obstacle on my current project.
The project is to build up a robot chassis. I have a 4-wheel chassis, an arduino Mega256 and a SMART 2-channel Motor Shield.

I wrote a sketch to provide various movements, and got it working as expected.

I then created a library of the same functions.

However, when I run the example sketch, it does not work as expected.

The code is:

.h file:

// ensure this library description is only included once
#ifndef Motorz_h
#define Motorz_h

// library interface description
class Motorz
{
  // user-accessible "public" interface
  public:
    Motorz(int speedL, int brkL, int dirL, int speedR, int brkR, int dirR);
    void EStop();
    void FwdSlow();
    void FwdFast();
    void BwdSlow();
    void BwdFast();
    void FwdLeft();
    void FwdRight();
    void BwdLeft();
    void BwdRight();
    void SpinLeft();
    void SpinRight();
    void Accel();  
    void DeAccel();    
  private:
    int _speedL;
    int _dirL;
    int _brkL;
    int _speedR;
    int _dirR;
    int _brkR;
};
#endif

.cpp file:

// include this library's description file
#include "Arduino.h"
#include "Motorz.h"

// Constructor 
Motorz::Motorz(int speedL, int brkL, int dirL, int speedR, int brkR, int dirR)
{
     // Left motor 
       pinMode(speedL, OUTPUT);
	_speedL = speedL;
       pinMode(brkL, OUTPUT); 
	_brkL= brkL;
       pinMode(dirL, OUTPUT); 
	_dirL = dirL;
     // Right motor 
       pinMode(speedR, OUTPUT); 
	_speedR = speedR;
       pinMode(brkR, OUTPUT); 
	_brkR= brkR;
       pinMode(dirR, OUTPUT);
	_dirR = dirR;

  // Left motor pin config
  int speedL = 3; 
  int brkL = 9; 
  int dirL = 12; 
  
  // Right motor pin config
  int speedR = 11; 
  int brkR = 8; 
  int dirR = 13;
*/	
}

void Motorz::EStop()
{
  analogWrite(_speedL, 0);     //Stops Motor L
  analogWrite(_speedR, 0);     //Stops Motor R
  digitalWrite(_brkL, HIGH); //Engage the Brake for Motor L
  digitalWrite(_brkR, HIGH); //Engage the Brake for Motor R
}
void Motorz::FwdSlow()
{
  //Move both motors forward @ slow speed
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, HIGH); //Establishes forward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 170); //Spins Motor L at slow speed
  analogWrite(_speedR, 170); //Spins Motor R at slow speed
}
void Motorz::FwdFast()
{
  //Move both motors forward @ fast speed
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, HIGH); //Establishes forward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 254); //Spins Motor L at fast speed
  analogWrite(_speedR, 254); //Spins Motor R at fast speed
}
void Motorz::BwdSlow()
{
  //Move both motors backward @ slow speed
  digitalWrite(_dirL, LOW); //Establishes backward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 170); //Spins Motor L at slow speed
  analogWrite(_speedR, 170); //Spins Motor R at slow speed
}
void Motorz::BwdFast()
{
  //Move both motors backward @ fast speed
  digitalWrite(_dirL, LOW); //Establishes backward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 254); //Spins Motor L at fast speed
  analogWrite(_speedR, 254); //Spins Motor R at fast speed
}
void Motorz::FwdLeft()
{
  //Slow Left turn
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, HIGH); //Establishes forward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 85); //Spins Motor L at very slow speed
  analogWrite(_speedR, 170); //Spins Motor R at slow speed
}
void Motorz::FwdRight()
{
  //Slow Left turn
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, HIGH); //Establishes forward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 170); //Spins Motor L at slow speed
  analogWrite(_speedR, 85);  //Spins Motor R at very slow speed
}
void Motorz::BwdLeft()
{
  //Slow Left turn
  digitalWrite(_dirL, LOW); //Establishes backward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 85); //Spins Motor L at fast speed
  analogWrite(_speedR, 170); //Spins Motor R at fast speed
}
void Motorz::BwdRight()
{
  //Slow Left turn
  digitalWrite(_dirL, LOW); //Establishes backward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 170); //Spins Motor L at fast speed
  analogWrite(_speedR, 85); //Spins Motor R at fast speed
}
void Motorz::SpinLeft()
{
  //Slow Left turn
  digitalWrite(_dirL, LOW); //Establishes backward direction of Motor L
  digitalWrite(_dirR, HIGH); //Establishes forward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 85); //Spins Motor L at fast speed
  analogWrite(_speedR, 85); //Spins Motor R at fast speed
}
void Motorz::SpinRight()
{
  //Slow Left turn
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  analogWrite(_speedL, 85); //Spins Motor L at fast speed
  analogWrite(_speedR, 85); //Spins Motor R at fast speed
}
void Motorz::Accel()
{
  //Slow Left turn
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
   for (int j = 0; j < 255; j += 10) 
	{ 	
	analogWrite(_speedL, j); //Spins Motor L accelerating to speed
	analogWrite(_speedR, j); //Spins Motor R accelerating to  speed
		delay (100);
	}  
}
void Motorz::DeAccel()
{
  //Slow Left turn
  digitalWrite(_dirL, HIGH); //Establishes forward direction of Motor L
  digitalWrite(_dirR, LOW); //Establishes backward direction of Motor R
  digitalWrite(_brkL, LOW); //Disengage the Brake for Motor L
  digitalWrite(_brkR, LOW); //Disengage the Brake for Motor R
  for (int j = 255; j < 0; j -= 10) 
	{ 	
	analogWrite(_speedL, j); //Spins Motor L deaccelerating to stop
	analogWrite(_speedR, j); //Spins Motor R deaccelerating to stop
		delay (100);
	}  
}

and finally, the example sketch:

// Link to the Motorz library
#include <Motorz.h>

Motorz Motorz(3, 9, 12, 11, 8, 13);

void setup() {
  // put your setup code here, to run once: 
}
void loop() {
  // put your main code here, to run repeatedly: 
  Motorz.Accel();
  Motorz.FwdFast();
  Motorz.DeAccel();
  Motorz.FwdLeft();
  Motorz.FwdFast();
  Motorz.EStop();
}

What I think is happening is that the sketch calls the first function (currently Motorz.Accel(); ), and then "moves" to the library, where it executes the relevant function.
Once there, it has no way to "get back" to the sketch to see what it should do next.

I'm not sure if I need something at the end of each function within the library, or if I need to call each function in a different way from within the sketch.

Can anyone offer any insights that might help?

Thanks
Andrew

Your Accel() function take at least 25.5 seconds to execute (255 times through the loop with a 100 millisecond delay each time). When it is done control will return to your loop() function.

My calculations would make it about 2.5 seconds, as the loop should run for 25 cycles... (the loop is stepping in 10s...)

I'll try running it later, and timing it to see if there is a point at which it moves to the next function...

Many thanks

Motorz::Motorz(int speedL, int brkL, int dirL, int speedR, int brkR, int dirR)
{
     // Left motor 
       pinMode(speedL, OUTPUT);
	_speedL = speedL;
       pinMode(brkL, OUTPUT); 
	_brkL= brkL;
       pinMode(dirL, OUTPUT); 
	_dirL = dirL;
     // Right motor 
       pinMode(speedR, OUTPUT); 
	_speedR = speedR;
       pinMode(brkR, OUTPUT); 
	_brkR= brkR;
       pinMode(dirR, OUTPUT);
	_dirR = dirR;

  // Left motor pin config
  int speedL = 3; 
  int brkL = 9; 
  int dirL = 12; 
  
  // Right motor pin config
  int speedR = 11; 
  int brkR = 8; 
  int dirR = 13;
*/	
}

Why do you have an end of comment marker in this method?

Calling pinMode() in the constructor of your class is not a good idea. Your constructor is called before the init() function, that sets up the hardware, so pinMode()'s actions could well get overwritten later.

You should have a begin() method, like all other class that use pins, where the mode is set.

abucksdiver:
My calculations would make it about 2.5 seconds, as the loop should run for 25 cycles... (the loop is stepping in 10s...)

I'll try running it later, and timing it to see if there is a point at which it moves to the next function...

Many thanks

So for 2.5 seconds, your rover is going to accelerate forward with no ability to abort? Does that really seem like a good idea?

I think you forgot a star-of-comment marker:

/*    <======= here ?
  // Left motor pin config
  int speedL = 3; 
  int brkL = 9; 
  int dirL = 12; 
  
  // Right motor pin config
  int speedR = 11; 
  int brkR = 8; 
  int dirR = 13;
*/

Tuxduino,
you are correct... I must have removed it when I was trying to get within the character limit of the post... my actual library code does include this...

/*
	// Left motor pin config
  int speedL = 3; 
  int brkL = 9; 
  int dirL = 12; 
  
  // Right motor pin config
  int speedR = 11; 
  int brkR = 8; 
  int dirR = 13;
*/

Regarding the non-aborting... you are right, I hadn't considered that!
I knew that this would be an iterative development process, I'm just working out what the next iteration needs to be !

Thanks guys...

I guess your project has an obstacle sensor of some sort. You could insert a sensor read inside the for loop in Accel and DeAccel functions, righe before or after the delay() call. That line would read like this (pseudocode)

if (obstacle detected) {
stopMotor
}

HTH

A couple recommendations:

Using delay() in any sort of sketch that needs to be responsive and handle multiple tasks is just a bad idea. Don't do it. Blink without delay is the proper way of timing actions without blocking other activities.

Implement a state machine for your rover. Google it, Wiki it (don't get caught up in complicated state machine patterns, you just need a switch/case based state machine). If you have trouble with implementation come back and ask some questions. The state machine itself should be pretty simple. Incorporating it with millis() based timing (ie Blink without delay) is a little more involved, but still not really complicated.

I suggest once you understand the delay() => millis() transition, you take a look at the timing libraries in this site's Libraries section. There's code that will make it easy to call one or more functions at specified intervals without you worrying about the details. You must first make the mental jump from sequential programming to state-based programming though (that came out way more buzz-wordy that I thought... :stuck_out_tongue: )

that came out way more buzz-wordy that I thought... :stuck_out_tongue:

But, it is correct. That describes properly the mind-set that is needed.

So far, I have a chassis that I can (just about) move forward, or backward, change it from stationary to moving, or moving to stationary, and that can make turns...

Yes, eventually, it will have sensors that allow obstacle-avoidance, and other stuff too.

You have all given me some good pointers to useful additional information and programming... I'll go and read up on your suggestions, and ask more dumb questions on the bits I don't understand!

Many thanks, all

I'll go and read up on your suggestions, and ask more dumb questions on the bits I don't understand!

If, after reading, you still have questions, they won't be dumb ones. They'll be ones that we like to see.

PaulS,
About your earlier comment:

Calling pinMode() in the constructor of your class is not a good idea. Your constructor is called before the init() function, that sets up the hardware, so pinMode()'s actions could well get overwritten later.

You should have a begin() method, like all other class that use pins, where the mode is set.

I've tried looking for information on the "begin() method", but only seem to find stuff related to Serial.begin()... can you please point me to something suitable so that I can further research this?

Many thanks
Andrew

Don't be fooled by the suggested method name. The point is, hardware initialization (i.e. pinMode(), etc.) should not be done inside the constructor, but in a separate method, that client code can call when appropriate, e.g. inside setup().
You could call this method begin(), hwInit() or whatever name you judge appropriate. I think begin() is a good suggestion because it would make your code consistent with other libraries, like Serial.