My Version of CreaBotLib

Fork of CreaBotLib by CreaLab

CreaBot.h

Committer:
sepp_nepp
Date:
2018-11-28
Revision:
6:4d8938b686a6
Parent:
5:efe80c5db389
Child:
7:3a793ddc3490

File content as of revision 6:4d8938b686a6:

/**
 * @file CreaBot.h
 * @brief File contains Creabot Library.
 
 * CreaBot.h contains the class Motor, and related enums and structs.
 * Includes "mbed.h" and "motor.h"
 
 * Refactorings:
 * All variables with suffixes "_cm_sec" = speeds in centimeters per second
 * MotCommand -> BotCommand
 * cmdbot_t -> BotCmdVerb
 * cm -> dist_cm
 
 * @author Tarek Lule, Francois Druilhe, et al.
 * @date 21. Nov. 2018.
 * @see https://os.mbed.com/users/sepp_nepp/code/CreaBotLib/  */
 
 // -------------------- Motor ---------------------------
 
#ifndef CREABOT_H
#define CREABOT_H

#include "mbed.h"
#include "motor.h"

#define MAX_SPEED_CM_SEC 30.0f /**< Clamp maximum advancement speed = 30cm/sec, was MAX_SPEED */
#define DEFAULT_SPEED_CM_SEC 2.0f /**< Default advancement speed = 2.0cm/sec, was DEFAULT_SPEED */
#define PI 3.141592f
#define DEPTH_FIFO 256  /**< Initialize the depth of the command FIFO to 256 */

/** \enum BotCmdVerb 
* \brief Robot Commands Verbs, gives the movement direction
*  */
typedef enum {
    IDLE = 0,   /**< Command to do nothing */  
    FORWARD,    /**< Advance the robot straight forward */  
    BACKWARD,   /**< Advance the robot straight backwards. */  
    ROTATE,     /**< Rotate around its own axis */  
    LEFT,       /**< Advance in a left curve */
    RIGHT,      /**< Advance in a right curve */
    REVLEFT,    /**< Reverse in a left curve */
    REVRIGHT    /**< Reverse in a right curve */
} BotCmdVerb;


/** \enum BotStatus 
* \brief Possible states of two motors of Bot
*  */
typedef enum {
    AlLSTOP = 0,/**< All Motors have stopped */  
    LMOT_RUNS,  /**< Left Motor still runs */  
    RMOT_RUNS,  /**< Right Motor still runs */  
    MOTORS_RUN  /**< Both Motors still run */  
} BotStatus;

/** \struct BotCommand
* \brief Structure of a Motor Command.

* The command structure is put into command FIFO, and treated by the FIFO-Handler */
typedef struct {
    BotCmdVerb command; /**< General Command to give movement direction.*/
    float dist_cm;      /**< Distance in dist_cm for translational movements .*/
    float angle_deg;    /**< Angle in degree for rotational movement .*/
    void set(BotCmdVerb Acommand, float Adist_cm, float Aangle_deg); /**< Helper; set structure fields to values  */
    void set(BotCmdVerb Acommand, float Adist_cm); /**< Helper; set structure fields to values  */
} BotCommand;

/** \class CommandFIFO
 * \brief 256 elements deep Command FIFO, to puts BotCommand in a queue.
 * 
 *  Internally stores all BotCommand in a static 256 array used as a circular ring buffer.
 *  Adds incoming commands at the head of the ring buffer at position writeIdx, 
 *  Gets oldest commands from the tail of the ring buffer at position readIdx,
 *  Keeps track of the occupied size in count.
 *  BotCommands are passed back as pointers.
 */
class CommandFIFO {
  public: 
    /** Class Creator: initializes an empties FIFO
    *
    * Ring buffer is allocated statically. Read and Write Index are set to 0. */
    CommandFIFO();
    
    /** Empty the FIFO.
    *
    * Since ring buffer is static, it suffice to set all pointers to 0, commands are left in memory. */
    void empty() {readIdx=writeIdx=count=0;};

    /** Reserve a new element at the head of the FIFO
    *
    *If FIFO is full, it passes back NULL 
    *Otherwise Advances the write index once and returns a pointer the next free command struct.
    *The caller then has to fills the command structure at that position. 
    *Do not free memory associated to the pointer.
    *
    *@return <BotCommand*> Pointer to the reserved BotCommand to write to. 
    */
    BotCommand *put();

    void put(BotCmdVerb Acommand, float Adist_cm, float Aangle_deg); 

    /** Get and remove the oldest element at the tail of the FIFO
    *
    *If FIFO is empty, it passes back NULL 
    *Otherwise advances the read index once and returns a pointer the oldest stored command in the FIFO.
    *Do not free memory associated with the pointer.
    *
    *@return <BotCommand*> Pointer to the oldest BotCommand. 
    */
    BotCommand *get();
    
    /** Access FIFO used count. 
    *
    *@return <int>  the number of commands in the FIFO */
    int getCount() {return count;}
    
     /** Check if FIFO is full. 
    * 
    * Space is limited to DEPTH_FIFO=256 BotCommand elements.
    * Should be checked before trying to put new elements
    *
    * @return <bool>  True if FIFO is full*/
    bool isFull() {return count>=DEPTH_FIFO;}
    
     /** Check if FIFO is empty. 
    * 
    * Should be checked before trying to get new elements
    * 
    * @return <bool>  True if FIFO is empty*/
    bool isEmpty() {return count<=0;}
    
  private:
    int readIdx;  /**< Index in FIFO array where to get the oldest element from. */
    int writeIdx; /**< Index in FIFO array where to put the next new element to. */
    int Count;    /**< Counts the number of elements in array used. */
    BotCommand cmd[DEPTH_FIFO]; /**< Actual static FIFO array where all elements reside. */
    BotCommand cmd_idle; /**< A Constant Idle command  */
};

/** \class Creabot

* \brief Synchronous Control of 2 motors as part of a two wheel robot
 *
 * Example:
 * @code
 * // --- Define the Four PINs & Time of movement used for Motor drive -----
 * Motor motorLeft(PA_12, PB_0, PB_1, PB_6); // Declare first the 2 motors (to avoid to have an object with 8 pins to create)
 * Motor motorRight(PA_5,PA_4,PA_3,PA_1);
 * Creabot mybot(&motorLeft, &motorRight, 10.0f,13.0f); // insert the motors and indicate wheel diameter and distance between wheels
 * 
 * int main() {
 * 
 *     mybot.setSpeed(12.5); // 12.5cm/s
 *     mybot.move(FORWARD,10); // Go forward of 10cm
 *     mybot.waitEndMove(); // Wait end of Move
 *     mybot.move(ROTATE,90); // Start rotation of 90° around the center between wheels (two wheels running in same direction at same speed)
 *     mybot.move(BACKWARD,40); // Stop immediately the rotation and go backward of 40cm
 *     mybot.waitEndMove(); // Wait end of Backward
 *     mybot.moveAndWait(LEFT,60); // Move Left of 60° in circle, center being the left wheel (off). Wait end of move
 *     mybot.waitEndMove();  // Not needed, as already waited... 
 *     mybot.moveAndWait(RIGHT,45, 33); // Move Right of 45°, center being at 33cm of the right wheel. Right wheel moving slower and on a shorter distance than left one. 
 *     mybot.moveAndWait(ROTATE,90);
 *     mybot.move(ROTATE,-90); // Opposite direction.
 *     mybot.waitEndMove(60); // with watchdog => if after 60s the move is not ended, continue the execution
 *     mybot.stopMove(); // Stop the movement before end...
 *     
 *     // Same with a fifo of command, opposite to the move, receiving a new command will not stop the current execution, but the bot will store it.
 *     mybot.fifo(FORWARD,10); // Already starting...
 *     mybot.fifo(BACKWARD,10); // will wait end of previous command to go
 *     mybot.fifo(ROTATE,120.0);
 *     mybot.fifo(LEFT, 30, 120);
 *     mybot.fifo(RIGHT, 25);
 *     mybot.waitEndMove(100000); // wait until fifo end... can flush anytime with stopMove...
 *     mybot.stopMove(); // before end... Flush the fifo and remove all instructions…
 * 
 *     while(1) {
 *     };
 * }
 * @endcode
 */
 
class Creabot {
public:
   /** Create a Creabot object with 2 motors
     *
     *  @param left Motor object declared before corresponding to left motor of the Creabot
     *  @param right Motor object declared before corresponding to right motor of the Creabot
     *  @param diameter_wheel_cm diameter in dist_cm of the wheels (both supposed to be at same diameter)
     *  @param distance_wheel_cm distance in dist_cm between center of left wheel and center of right wheel
     */
    Creabot(Motor *left, Motor *right, float diameter_wheel_cm, float distance_wheel_cm);
    
    /** Property access to Motor state */
    BotState getState() {return MotState};
    
    void setSpeed(float speed_cm_sec);
    void waitEndMove();
    void waitEndMove(uint32_t delay_us); // watchdog
    void setCallBack(void (*Acallback)(int status));
    void moveAndWait(BotCmdVerb moveType, float angle_or_cm);
    void moveAndWait(BotCmdVerb moveType, float angle_deg, float dist_cm);
    void move(BotCmdVerb moveType, float angle_or_cm);
    void move(BotCmdVerb moveType, float angle_deg, float dist_cm);
    void fifo(BotCmdVerb moveType, float angle_or_cm);
    void fifo(BotCmdVerb moveType, float angle_deg, float dist_cm);
    void flushFifo();
    void spirale(float b, float turns);
    int moveInFifo();
    void executeFifo();
    void stopMove();
         
private:
    void moveForward(float dist_cm);
    void moveBackward(float dist_cm);
    void rotate(float angle_deg);
    void moveRight(float angle_deg);
    void moveRight(float angle_deg, float center_cm);
    void moveLeft(float angle_deg);
    void moveLeft(float angle_deg, float center_cm);
    uint32_t computeSpeed(Motor *motor, float speed_cm_sec);
    
    void (*extCallBack)(int status);
    void moveMotorLeft(motorDir dir, float angle_deg);
    void moveMotorRight(motorDir dir, float angle_deg);
    void executeCommand(BotCommand *cmd);
    void setSpeedMot(Motor *motor, float speed_cm_sec);

    
  private: 
    // The two motors and their physical properties:
    // Two call back functions that are called back by the motors when they have stopped
    void cbLeftMotStopped();
    void cbRightMotStopped();
    void AllMotorsStopped();
    Motor *motor_left;
    Motor *motor_right;
    float diameter_wheel;
    float distance_wheel;
    float perimeter_wheel;
    float perimeter_bot;
    float degree_wheel_per_cm;
    float degree_bot_per_cm;
    float ratio_wheel_bot;


    float last_speed;  // last requested speed
    CommandFIFO fifoBot;
    BotCommand current_cmd;
    Ticker botTicker;
    bool executingFifo;
    
    BotState MotState;
  private:
    /* members that were not used in last release
     * float macro_move_parameter;
     * BotCommand macro_move;
     * void setSpeedLeft(float speed_cm_sec);
     * void setSpeedRight(float speed_cm_sec); */
};

#endif