Hello,
I'm trying to build a somewhat simple application on an Arduino. I have a pneumatic ram that I'll be controlling push and pull force with via two switching solenoids. It's for a testing apparatus, so I'm trying to build out a menu system that lets me predefine things like, cycle frequency, number of cycles, total run time etc. then hit start and have it run. While I could probably do this as one big main.cpp file, I really like the practice of breaking up my code into custom libraries then including them (though admittedly my knowledge of the "how's" of this can be limited).
My whole main.cpp:
#include <Arduino.h>
#include <REPTestOS.h>
REPTestOS OS; //create now Operating System object
void setup()
{
OS.bootOS();
}
void loop()
{
OS.runOS();
}
I have three libraries I'm building. PnumaControl to manage actuators, REPTestOS_menus this is the tcmenu, and REPTestOS to control everything, imports both other libraries.
This is the main library that I'm trying to join everything together with. It imports PnumaControl.h and REPTestOS_menus.h
#include "REPTestOS.h"
#include "Util.h"
//global variable definitions
Util util;
PnumaControl pnuma1(9, 10);
REPTestOS::REPTestOS(){}; //constructor
REPTestOS::~REPTestOS(){}; //destructor
void REPTestOS::bootOS() //boot operating system function. To run in startup
{
Wire.begin(); //Start wire
setupMenu(); //Initialize menu system
Serial.begin(9600); // initialize serial communication at 9600 bits per second:
Serial.println("Booting"); //small serial indicator during boot phase
//Start remaining items
}
void REPTestOS::runOS() //constantly runs in loop
{
taskManager.runLoop(); //handler for menu system task management
}
/*----------------------------------------------------------
------------------------------------------------------------
----------------- Menu System Handlers ---------------------
------------------------------------------------------------
----------------------------------------------------------*/
void CALLBACK_FUNCTION cycleFrequency(int id)
{
pnuma1.cyclesPerSecond = int(menuTestSettingsCyclesPerSecond.getAsFloatingPointValue()); //update pnuma1 with value
}
void CALLBACK_FUNCTION pullControl(int id)
{
pnuma1.setMode(menuTestSettingsPush.getBoolean(), menuTestSettingsPull.getBoolean()); //update pnuma1 with mode
}
void CALLBACK_FUNCTION pushControl(int id)
{
pnuma1.setMode(menuTestSettingsPush.getBoolean(), menuTestSettingsPull.getBoolean()); //update pnuma1 with mode
}
void CALLBACK_FUNCTION stopTest(int id)
{
pnuma1.running = false;
}
void CALLBACK_FUNCTION startTest(int id)
{
pnuma1.running = true;
}
and here is the beginning of PnumaControl.cpp, she's rather long:
PnumaControl::PnumaControl(int pushIn, int pullIn)
{
pushPin = pushIn; //constructor requires push and pull actuator pin #'s, set to private
pullPin = pullIn;
}
PnumaControl::~PnumaControl()
{
}
void PnumaControl::setup()
{
pinMode(pushPin, OUTPUT);
pinMode(pullPin, OUTPUT);
digitalWrite(pushPin, LOW);
digitalWrite(pullPin, LOW);
}
void PnumaControl::control()
{
if (running)
{
baseClock = millis(); //update clock
unsigned long timeDelta = baseClock - lastActuation; //find time difference between last actuation
int freq = 1000 / cyclesPerSecond; //compare to desired frequency
if (timeDelta > freq)
{
setNextCycle(); //update state based off of mode
actuate(); //fire updated actuation state
lastActuation = millis(); //reset timer
}
}
};
I'm currently running into an issue with the callback functions. An issue which I'm certain is my approach, not a limitation of the way tcmenu is built. If I define a
global instance of PnumaControl, within REPTestOS, I have access to it within the callback functions which I've moved to REPTestOS, but I then do not have access to it within public member functions of REPTestOS, this is the current code, and from my reading, bad practice. On the contrary, if I create an instance of PnumaControl at main.cpp, (where I'm also creating the REPTestOS instance) and pass it to the REPTestOS instance, I then have access to it from within the public member functions of REPTestOS, but I don't have the ability to access it from the callback functions.
I'd like to have the ability to call "pnuma1.control()" in conjunction with "taskmanager.runLoop()" so that as the state of my actuator is manipulated, it is managed.
From the reading I have done it appears to be a scoping issue because the callback functions are "static member functions" meaning they don't play nice with one another. I'm not familiar enough with them to work around this. Would love some assistance if you could!
I've linked the project so you can see everything if I've not been complete enough with my snippets.