From 6648fe43b0a7df3581416beedb3181a38e563533 Mon Sep 17 00:00:00 2001 From: Tomalaya <31702587+Tomalaya@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:20:12 -0500 Subject: [PATCH 1/3] New Basic Robot program with some helper classes to look more like RobotC equivalent functionality --- examples/BasicRobot/ArcadeDrive.ino | 35 ++++ examples/BasicRobot/PositionalServo.h | 221 ++++++++++++++++++++++++++ examples/BasicRobot/StatefulButton.h | 93 +++++++++++ examples/BasicRobot/Tasks.h | 120 ++++++++++++++ 4 files changed, 469 insertions(+) create mode 100644 examples/BasicRobot/ArcadeDrive.ino create mode 100644 examples/BasicRobot/PositionalServo.h create mode 100644 examples/BasicRobot/StatefulButton.h create mode 100644 examples/BasicRobot/Tasks.h diff --git a/examples/BasicRobot/ArcadeDrive.ino b/examples/BasicRobot/ArcadeDrive.ino new file mode 100644 index 0000000..bff88c8 --- /dev/null +++ b/examples/BasicRobot/ArcadeDrive.ino @@ -0,0 +1,35 @@ +#include "Gizmo.h" + +#define MAXMAG 90 + +int rampStep = 0; + +int SoftenMagnitude(int mag) { + + if (abs(mag) < 1) { + return 0; //center deadzone + } + + return (mag<0 ? -1:1 )* log(abs(mag)) * MAXMAG / log(MAXMAG); + float adj = (mag * mag) / MAXMAG; + return (mag < 0 ? 1 : -1 )* (int)adj; +} + +//Ramp up across .75 seconds +#define MAXRAMP 15 + +void ArcadeTarget(int XAXIS, int YAXIS, int &targetL, int &targetR) { + int x = SoftenMagnitude(map(gizmo.getAxis(XAXIS), 0, 255, -90, 90)); + int y = SoftenMagnitude(map(gizmo.getAxis(YAXIS), 0, 255, -90, 90)); + + if (abs(y)>30) x=x/2; + + if (abs(x)+abs(y)<20) { + rampStep = 1; + } else { + rampStep = MIN(rampStep+1, MAXRAMP); + } + + targetR = (MAX(MIN(y + x,90),-90)*rampStep/MAXRAMP) + MAXMAG; + targetL = (MIN(MAX(y - x,-90),90)*rampStep/MAXRAMP) + MAXMAG; +} diff --git a/examples/BasicRobot/PositionalServo.h b/examples/BasicRobot/PositionalServo.h new file mode 100644 index 0000000..a838a40 --- /dev/null +++ b/examples/BasicRobot/PositionalServo.h @@ -0,0 +1,221 @@ +#ifndef BESTPositionalServo_h +#define BESTPositionalServo_h + +#include "Gizmo.h" + +//Positional Speed Values for the Servo. The higher selected, the faster the servo will go. +//These affect the number of degrees the servo jumps per interval plus how quickly it accelerates over time while its control is depressed +typedef enum { + PS_SPEED_NONE = -1, + PS_SPEED_SLOTH = 0, + PS_SPEED_SLOW, + PS_SPEED_MEDIUM, + PS_SPEED_FAST, + PS_SPEED_ULTRA +} PS_SPEED; + +/* Positionaal Servo Class. + * This class can be use to control a servo, maintining it at a set position or advancing it with the use of 2 buttons OR an axis. + * It can also add in accelearation the longer a control is held, helping give fine control or broad movements + */ +class PositionalServo { +public: + PositionalServo(); //Constructor + + /** + * init - This function does internal setup for the Positional Servo to be used with 2 buttons, and must be called during setup phase + * @param {int} motorId - The GIZMO_MOTOR_XXX port where the Servo is attached + * @param {int} btnA - used with btnB, the GIZMO_BUTTON_XXX value to decrement the servo position + * @param {int} btnB - used with btnB, the GIZMO_BUTTON_XXX value to advance the servo position + * @param {PS_SPEED} (OPTIONAL) - Speed servo should move, defaults to PS_SPEED_MEDIUM + * @param {int} (OPTIONAL) defpos - servo position, defaults to 90, right in the middle + * @param {bool} (OPTIONAL) useAcceleration - set to true iff the servo should speed up the longer a button or axis direction is held. Defaults to true + */ + void init(int motorId, int btnA, int btnB, PS_SPEED speed = PS_SPEED_MEDIUM, int defpos = 90, bool useAcceleration = true); + + + /** + * init - This function does internal setup for the Positional Servo to be used with an axis, and must be called during setup phase + * @param {int} motorId - The GIZMO_MOTOR_XXX port where the Servo is attached + * @param {int} Axis - by istelf, the GIZMO_AXIS_XXX to use to decrement or advance the Servo + * @param {PS_SPEED} (OPTIONAL) - Speed servo should move, defaults to PS_SPEED_MEDIUM + * @param {int} (OPTIONAL) defpos - servo position, defaults to 90, right in the middle + * @param {bool} (OPTIONAL) useAcceleration - set to true iff the servo should speed up the longer a button or axis direction is held. Defaults to true + */ + void init(int motorId, int Axis, PS_SPEED speed = PS_SPEED_MEDIUM, int defpos = 90, bool useAcceleration = true); + + /** + * setDefaultPosition - Set default position for the servo. Typically defaults to 90, right in the middle. + * This is only needed to override a previous default set in either the init call or to setDefaultPosition + * @param {int} defpos - set true to update the position of the servo to the enw default now + * @param {bool} (Optional) update - set to false to prevent the position from changing to the new defualt immediately + */ + void setDefaultPosition(int defpos, bool update=true); + + /** + * setSpeed - Set speed of the servo, defaults to PS_SPEED_MEDIUM. + * This is only needed to override a previous default set in either the init call or to setDefaultPosition + * @param {PS_SPEED} Speed - sets the speed the servo should move, from PS_SPEED_SLOTH to PS_SPEED_ULTRA, with PS_SPEED_SLOTH being the slowest + */ + void setSpeed(PS_SPEED Speed); + + /** + * setAcceleration - Set whether the servo should accelartion th3 longer a button or axis position is held, default to true. + * This is only needed to override a previous default set in either the init call or to setDefaultPosition + * @param {bool} useAcceleration - set to true if the servo should speed up the longer a button or axis direction is held + */ + void setAcceleration(bool useAcceleration); + + /** + * reset - Reset a servo back to its defualt position + */ + void reset(); + + /** + * update - Let a Servo process its position during the main loop + * @param {bool} (OPTIONAL) bReverse) - Set true to move the servo in the opposite direction + */ + void update(bool bReverse = false); + + private: + void init(int motorId, PS_SPEED speed, int defpos, bool useAcceleration); + int _initPos; + int _pos; + int _last; + int _step; + int _count; + int _btnUp; + int _btnDown; + int _Axis; + PS_SPEED _lastSpeed; + int _StepInt; + int _StepSize; + int _StepInc; + int _StepMax; + + Servo _motor; +}; + + +PositionalServo::PositionalServo() {} + +//Private Init function for inernal ffinal setup +void PositionalServo::init(int motorId, PS_SPEED speed, int defpos, bool useAcceleration) { + _last = _step = _count = 0; //reset all counters + _initPos = _pos = defpos; //Set initial and defual tpositions + _StepInt = useAcceleration ? 1 : -1; //Set initial step for accelerations + setSpeed(speed); //This call set final step interval, size and magnitude for accelration + _motor.attach(motorId); //Attach Motor + reset(); //Reset servo to default position to sync with these settings +} + +void PositionalServo::init(int motorId, int btnA, int btnB, PS_SPEED speed, int defpos, bool useAcceleration) { + //Init when using buttons + _btnUp = btnA; //Assign Bittons + _btnDown = btnB; + _Axis = -1; //Clear Axis + init(motorId, speed, defpos, useAcceleration); //Finish common init +} + +void PositionalServo::init(int motorId, int Axis, PS_SPEED speed, int defpos, bool useAcceleration) { + //Init when using an axis + _btnUp = _btnDown = -1; //CLear Buttons + _Axis = Axis; //Assign Axis + init(motorId, speed, defpos, useAcceleration); //Finish common init +} + +void PositionalServo::setDefaultPosition(int defPos, bool update) { + //Set a new default posiiton. + _initPos = defPos; + if (update) { reset(); } +} + + +void PositionalServo::setSpeed(PS_SPEED Speed) { + //Set servo speed. Servo speed is based on 3 factors: + // _StepInt - interval, how many loops have to go by before an update to acceleration is consiedered + // _StepSize - How many degrees to jump when changing positions, static when acceleration is not being used, otherwise growing + // _StepMax - Maximum step sie to grow to, when accelerating + _lastSpeed = Speed == PS_SPEED_NONE ? _lastSpeed : Speed; // If speed is none, this is just an update of the speed to reset Int, Size, and Max + switch(_lastSpeed) { + case PS_SPEED_SLOTH: //Go real slow + if (_StepInt>0) _StepInt = 5; + _StepSize = 2; + _StepMax = 30; + break; + + case PS_SPEED_SLOW: //Go kinda slow + if (_StepInt>0) _StepInt = 4; + _StepSize = 3; + _StepMax = 30; + break; + + case PS_SPEED_MEDIUM: //Go middle-ish + if (_StepInt>0) _StepInt = 3; + _StepSize = 6; + _StepMax = 40; + break; + + case PS_SPEED_FAST: //Go Kinda Fast + if (_StepInt>0) _StepInt = 2; + _StepSize = 10; + _StepMax = 50; + break; + + case PS_SPEED_ULTRA: //Go Fast + default: + if (_StepInt>0) _StepInt = 1; + _StepSize = 20; + _StepMax = 60; + break; + } + +} + +void PositionalServo::setAcceleration(bool useAcceleration) { + //Set whether to use acceleration or not. Setting Int below zero negates acceleration + _StepInt = useAcceleration ? 1 : -1; + setSpeed(PS_SPEED_NONE); +} + +void PositionalServo::reset() { + //Reset to out initial positions. Clear any counters + _pos = _initPos; + _last = _step = _count = 0; + _motor.write(_initPos); +} + +void PositionalServo::update(bool goReverse) { + //Cacluate and update our position, checking if controls are active + bool btnUp = false; + bool btnDown = false; + + if (_btnUp != -1 && _btnDown != -1) { //Using buttons controls, get buttin states from gizmo + btnUp = gizmo.getButton(_btnUp); + btnDown = gizmo.getButton(_btnDown); + } else if (_Axis != -1) { //Using axis controls, get axis state from gizmo, but just treat it as tertiary, its eitehr considered full tilt on way, the other, or in the middle + int val = map(gizmo.getAxis(_Axis), 0, 255, -1, 1); + btnUp = val < 0; + btnDown = val > 0; + } + if (btnUp) { //Up control is is use + if (_step <= 0) {_step = _StepSize; _count=0;} //If step has been zeroed or changed direction, reset it to beginning values and acceleration + _pos = MIN(180,_pos+_step); //Set our new position based on step, but make sure to not go over 180 + if (_StepInt > 0 && _count++ > _StepInt) { _count = 0; _step = MIN(_step+_StepSize,_StepMax); } //if it is time to acccelerate, up the step size, but don't go over max + } else if (btnDown) { //Down control is in use + if (_step >= 0) {_step = -1 * _StepSize; _count=0;} //If step has been zeroed or changed direction, reset it to beginning values and acceleration + _pos = MAX(0,_pos+_step); //Set our new position based on step, but make sure to not go below 0 + if (_StepInt > 0 && _count++ > _StepInt) { _count = 0; _step = MAX(_step-_StepSize,-1 * _StepMax); } //if it is time to acccelerate, up the step size, but don't go ov + } else { + //No control is use, zero out conters to reset any acceleration + _count = 0; + _step = 0; + } + + if (_last != _pos) { //Only write if a new position has been calculated + _motor.write(goReverse ? 180-_pos:_pos); //write it to the servo, reversing as needed + _last = _pos; //Store this new position for future checks + } +} + +#endif //BESTPositionalServo_h diff --git a/examples/BasicRobot/StatefulButton.h b/examples/BasicRobot/StatefulButton.h new file mode 100644 index 0000000..24df2c4 --- /dev/null +++ b/examples/BasicRobot/StatefulButton.h @@ -0,0 +1,93 @@ +#ifndef BESTStatefulButton_h +#define BESTStatefulButton_h + +#include "Gizmo.h" + +/* Stateful Button Class. + * This class read values for an Input from the Gizmo, and can remember state for it to return + * transitions or current status. Sometimes referred to as a latching button. This class can be used on a button or a single side of an axis + */ +class StatefulButton { +public: + StatefulButton(); //Constrctor + + /** + * init - This function does internal setup for the Stateful Button, and must be called during setup phase + * @param {int} BtnId - The GIZMO_BUTTON_XXX id for this button to use + */ + void init(int BtnId); + + /** + * init - This function does internal setup for the Stateful Button, and must be called during setup phase + * @param {int} BtnId - The GIXMO_AXIS_XXX id for this button to use + * @param {SBAxisPos} AxisPos - When using GIXMO_AXIS_XXX as id, Set to false for the values below 90 on the Axis and true for those above + */ + void init(int AxisId, bool bLower); + + /** + * clicked - See if Stateful button has just been pressed. + * @returns {bool} - true iff the button has just been pressed and is now in the down position + */ + bool clicked(); + + /** + * released - See if Stateful button has just been released. + * @returns {bool} - true iff the button has just been released and is now in the up position + */ + bool released(); + + /** + * isDown - See if Stateful button is actively being pushed + * @returns {bool} - true iff the button has is currently down + */ + bool isDown(); + + private: + void update(); + int _id; + int _lastState; + int _state; + int _Axis; +}; + +StatefulButton::StatefulButton() {} + +void StatefulButton::init(int BtnId) { + //Init as a button + _id = BtnId; //Set button gizmo id + _Axis = 0; //zero axis use + _state = _lastState = false; //clear any state +} + +void StatefulButton::init(int AxisId, bool bLower) { + //init as an Axis + _id = AxisId; //Set button axis id + _Axis = bLower ? 1 : -1; //Mark if it is for the lower or upper portion of an axis + _state = _lastState = false; //clear any state +} + +bool StatefulButton::clicked() { + update(); //Update from gizmo + return _state && !_lastState; //We're only clicked when gizmo said button is down, when on the last check it wasn't +} + +bool StatefulButton::released() { + update(); //Update from gizmo + return !_state && _lastState; //We're only release when gizmo said button is up, when on the last check it wasn't +} + +bool StatefulButton::isDown() { + update(); //Update from gizmo + return _state; //Return current state +} + +void StatefulButton::update() { + _lastState = _state; //Remember our last state <-- this is the crux of this entire control + if (0 != _Axis) { //Using an axis control + int val = map(gizmo.getAxis(_id), 0, 255, -10, 10); //Read in the axis. We only worry if it is one side or the other + _state = _Axis == (val < -1 ? -1 : (val > 1 ? 1 : 0)); //Match it to our axis, -1 for below or 1 for above + } else { + _state = gizmo.getButton(_id); //using a button, just read its state + } +} +#endif //BESTStatefulButton_h \ No newline at end of file diff --git a/examples/BasicRobot/Tasks.h b/examples/BasicRobot/Tasks.h new file mode 100644 index 0000000..6fa082b --- /dev/null +++ b/examples/BasicRobot/Tasks.h @@ -0,0 +1,120 @@ +#ifndef BESTTask_h +#define BESTTask_h + +typedef int (Task)(int); +typedef void (TaskSetup)(); + +/* Example usage for tasks Class + in main ino file, or your own other file, create function for Drive setup and loop + void DriveSetup() { + ... get ready to do cool stuff ... + } + + int DriveTask(int runStep) { + ... do cool stuff ... + } + + in main setup(), create your task with a name, address to a function to execute as its loop, and an optional setup function address + void setup() { + ... do other stuff + Tasks.Create("DRIVE", &DriveTask, &DriveSetup); + Tasks.Create("LEDS", &BlinkEm); + ... + Tasks.Create("ARM", &GoArmGo); + } + + in main loop(), ensure Tasks class runs all of its tasks, no delay needed - tasks takes care of that as long as everything runs in a task + void loop() { + Tasks.Update(); + } +*/ + + +// Managed subtask the TaskManager controls +class subTask { + public: + subTask() {_runStep = _nextTime =0; _loopFnc = NULL; _Next = NULL;}; + char* _name; //Subtask hman readable name + Task* _loopFnc; //Funciton to call when looping + int _runStep; //numebr of iteration loop has been called + int _nextTime; //time when it should call loop again + subTask* _Next; //Linked list pointer to next subtask in list +}; + +/* TaskManager Class. + * This class builds a manager to let independent tasks run on an Arduion IDE code base. Each task time slices, and returns back milliseconds until it wants to trun again + */ +class TaskManager { +public: + TaskManager(); //Constrctor + + /** + * Create - Create a new task, this is called during setup phase. + * @param {Task} loopFnc - Loop fucntion Task to call when running in loop mode. Of type int fnc(int). A Loop function should rturn an integer value indicating milliseconds until the next time it wants to run, and is passed in a count of the numbe rof iterations it has so far run + * @param {setupFnc} (OPTIONAL) setupFnc - void functon to call if setup is needed for the task, of type void fnc(). + */ + void Create(const char* name, Task* loopFnc, TaskSetup *setupFnc = NULL); + + /** + * Update - Update all tasks while running in loop + */ + void Update(); + + private: + subTask _subTasks; //Linked list of subtasks, initial one allocated in class +}; + +#include "Tasks.h" + +TaskManager::TaskManager() {} //Constructor + +void TaskManager::Create(const char *name, Task* loopFnc, TaskSetup* setupFnc) { + subTask* task = &_subTasks; //Gte head of our linked lists of tasks + + while (task->_loopFnc) { //Look until we find a subtask that doesn't yet has a mandatory loop function defined + if (!task->_Next) { //If we hit the end of the list, allocate a new one + task->_Next = new subTask(); + } + task = task->_Next; //Advance the list to next entry + } + + //This should be an empty subtask. Set it's name and loop function + task->_name = (char *)name; + task->_loopFnc = loopFnc; + + if (setupFnc) { //If it has a stup function, call it now + (*setupFnc)(); + } + +} + +void TaskManager::Update() { + //Update. Loop through our subtasks, and if any are scheduled to run, run them + int now = millis(); + int nextRun = now + 2000; //default to at least check every 2 seconds if we should run + + subTask* task = &_subTasks; //Start at the head of our subtasks list + + while (task) { + if (task->_loopFnc && task->_nextTime <= now) { //valid task says it should run becasue its next time is now or before now + task->_nextTime = millis() + (*(task->_loopFnc))(task->_runStep); //Execute its loop, getting back a value for when it should run again + task->_runStep = task->_runStep < 0x0FFFFFFF ? task->_runStep + 1 : 0; //Increment its runStep, ensuring not to overflow + } + //Serial.printf("TASK %s next in %d\r\n", task->_name, task->_nextTime - millis()); + nextRun = MIN(task->_nextTime, nextRun); //If its next time is hsorter than our expected next time, remeber it for setting overall delay + task = task->_Next; //Loop to the next subtask + } + + //Schedule our delay before allowing loop again + now = millis(); + int wait = nextRun > now ? nextRun - now : 1; + //Serial.printf("Delaying %d before next task eval\r\n", wait); + delay(wait); +} + +/* TaskManager + * Define tasks that can be time sliced and run independently. THey are created in Tasks, and then execute their loo funciton when their time is due + */ +TaskManager Tasks; + +#endif //BESTTask_h \ No newline at end of file From 4017b599c60a89e0da2a1d4ab7ca680a4f05b2c9 Mon Sep 17 00:00:00 2001 From: Tomalaya <31702587+Tomalaya@users.noreply.github.com> Date: Thu, 11 Apr 2024 14:20:26 -0500 Subject: [PATCH 2/3] New Basic Robot program with some helper classes to look more like RobotC equivalent functionality --- examples/BasicRobot/BasicRobot.ino | 88 ++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/examples/BasicRobot/BasicRobot.ino b/examples/BasicRobot/BasicRobot.ino index 6525077..73175ad 100644 --- a/examples/BasicRobot/BasicRobot.ino +++ b/examples/BasicRobot/BasicRobot.ino @@ -1,30 +1,61 @@ #include #include "Gizmo.h" +// The Gizmo provides access to the data that is held by the field +// management system and the gizmo system processor. +Gizmo gizmo; + +#include "PositionalServo.h" +#include "StatefulButton.h" +//#include "Tasks.h" //Un-comment to make use tasks for splitting up code + // Define a left and right drive motor. Connected via MC-29 motor // controllers they appear as servos to the system. Servo DriveL, DriveR; -// The Gizmo provides access to the data that is held by the field -// management system and the gizmo system processor. -Gizmo gizmo; +// Define a motor to sue for the arm +Servo Arm; + +// Define a claw using a positional servo. This will keep the servo in a posotion as its controls are used +PositionalServo Claw; + +//Create a Button to toggle into and out of Arcade Mode +StatefulButton BtnStart; + +//By default, start wth Arcade mode disabled +bool bArcadeMode = false; // Initialize the hardware and configure libraries for use. void setup() { // Initialize the connection to the system processor. gizmo.begin(); - // Configure the I/O mode for the motor driver pins. + // Configure the I/O mode for the motor driver pins and claw pinMode(GIZMO_MOTOR_1, OUTPUT); - pinMode(GIZMO_MOTOR_2, OUTPUT); + pinMode(GIZMO_MOTOR_8, OUTPUT); + pinMode(GIZMO_MOTOR_4, OUTPUT); + pinMode(GIZMO_MOTOR_5, OUTPUT); // Configure the builtin LED so we can tell the program is running. pinMode(LED_BUILTIN, OUTPUT); // Attach the motor controller objects to the ports the motors are // connected to. - DriveL.attach(GIZMO_MOTOR_1); - DriveR.attach(GIZMO_MOTOR_2); + DriveR.attach(GIZMO_MOTOR_1); + DriveL.attach(GIZMO_MOTOR_8); + Arm.attach(GIZMO_MOTOR_5); + + //Initialize the position claw on port 4 using left trigger and bumber buttons + Claw.init(GIZMO_MOTOR_4, GIZMO_BUTTON_LT, GIZMO_BUTTON_LSHOULDER, PS_SPEED_ULTRA); + + + //Use serial for Debug output + Serial.begin(9600); + + //Give serial startup a chance to get going + delay(500); + + Serial.println("BASIC ROBOT READY TO GO"); } // Runs in a loop to perform tasks that are required to run the robot. @@ -36,21 +67,42 @@ void loop() { // Refreshes the information about axis and button state. gizmo.refresh(); - // Fetch the speed of each axis, then convert this to the range - // expected by the motors. + //If start button gets clicked, toggle Arcade Mode + if (BtnStart.clicked()) { + bArcadeMode = !bArcadeMode; + Serial.printf("Drive Mode is now %s\r\n", bArcadeMode ? "ARCADE" : "TANK"); + } + int targetL, targetR; - targetL = map(gizmo.getAxis(GIZMO_AXIS_LY), 0, 255, 0, 180); - targetR = map(gizmo.getAxis(GIZMO_AXIS_RY), 0, 255, 0, 180); + if (bArcadeMode) { + //Use arcade class to determine left and right motor speeds + ArcadeTarget(GIZMO_AXIS_LX, GIZMO_AXIS_LY, targetL, targetR); + } else { + // Fetch the speed of each axis, then convert this to the range + // expected by the motors. + targetL = map(gizmo.getAxis(GIZMO_AXIS_LY), 0, 255, 0, 180); + targetR = map(gizmo.getAxis(GIZMO_AXIS_RY), 0, 255, 0, 180); + } + // Write the target speeds to the motor controllers. DriveL.write(targetL); DriveR.write(targetR); - // Sleep for 20ms, which means this loop will run at ~50Hz. This is - // because in this sample code all we do is get control inputs and - // map them to motors to drive around, so we don't need to go any - // faster. You should probably remove this in your code so that - // your main loop runs faster when polling sensors or animating - // lights. - delay(20); + // Update our claw position + Claw.update(); + + if (gizmo.getButton(GIZMO_BUTTON_RT)) { + //if right trigger is pressed, send arm motor forwards + Arm.write(180); + } else if (gizmo.getButton(GIZMO_BUTTON_RSHOULDER)) { + //if right shoulder is pressed, send ar motor backwards + Arm.write(0); + } else { + //if neither of thr right trigger buttons is pushed, let arm know to stop + Arm.write(90); + } + + // Sleep for 50ms, which means this loop will run at ~20Hz. + delay(50); } From 6a3e38e912b44b2b0304d2f018703c1cedb24b59 Mon Sep 17 00:00:00 2001 From: Tomalaya <31702587+Tomalaya@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:38:23 -0500 Subject: [PATCH 3/3] BEST references Removed Removed references to BEST in re-entry check ifdefs --- examples/BasicRobot/BasicRobotSources.zip | Bin 0 -> 9633 bytes examples/BasicRobot/PositionalServo.h | 6 +++--- examples/BasicRobot/StatefulButton.h | 6 +++--- examples/BasicRobot/Tasks.h | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 examples/BasicRobot/BasicRobotSources.zip diff --git a/examples/BasicRobot/BasicRobotSources.zip b/examples/BasicRobot/BasicRobotSources.zip new file mode 100644 index 0000000000000000000000000000000000000000..5dda1c397a6dd3846031da9209e85e7eaefa4102 GIT binary patch literal 9633 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