If you use Gitkraken, immediately update to version 8.1 (or later) remove your SSH key from https://gitlab.ai.vub.ac.be/-/profile/keys and generate a new one. SSH keys generated with a vulnerable Gitkraken version are compromised.

Commit 27d53695 authored by Niels Post's avatar Niels Post
Browse files

Update 16-10

- Partly commented
- Movement is now implemented
parent a06d4dcf
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
CMakeListsPrivate.txt CMakeListsPrivate.txt
cmake-build-*/ cmake-build-*/
CMakeLists.txt CMakeLists.txt
\ No newline at end of file
...@@ -5,28 +5,60 @@ ...@@ -5,28 +5,60 @@
#include <communication/handler/ActionCommandHandler.hpp> #include <communication/handler/ActionCommandHandler.hpp>
#include <communication/handler/MeasurementCommandHandler.hpp> #include <communication/handler/MeasurementCommandHandler.hpp>
#include <queue> #include <queue>
#include <communication/command/Command.hpp>
#include <communication/command/ReturnCommand.hpp>
class PMSVSettings; class PMSVSettings;
class Command;
class ReturnCommand; class ReturnCommand;
/**
* Controller for the wireless communication aspect of the robot.
*
* This controller continuously checks for received RF24 Commands, parses them, and invokes a \refitem{CommandHandler} for them.
* The controller then transmits the ReturnCode from the handler to the sender of the command
*/
class CommunicationController { class CommunicationController {
private: private:
/// The radio used to communicate with the other party
RF24 nrfRadio; RF24 nrfRadio;
/// A handler for commands in the category GENERAL
GeneralCommandHandler generalCommandHandler; GeneralCommandHandler generalCommandHandler;
/// A handler for commands in the category ACTION
ActionCommandHandler actionCommandHandler; ActionCommandHandler actionCommandHandler;
/// A handler for commands in the category MEASUREMENT
MeasurementCommandHandler measurementCommandHandler; MeasurementCommandHandler measurementCommandHandler;
/// Queue of commands that are still to be handled
std::queue<Command> commandQueue; std::queue<Command> commandQueue;
protected: protected:
void handleCommand(const Command &command); /**
void sendReturnCommand(const ReturnCommand &command); * Retrieve the next command from the queue, and handle it.
*/
void handleQueuedCommand();
/**
* Send a ReturnCommand as a result of a Command
* @param returnCommand The returnCommand to send
*/
void sendReturnCommand(const ReturnCommand &returnCommand);
/**
* If data is available on RF24, try to parse the data as command, and add it to the commandQueue
*
* When no data is available, this function returns
* When a command is inproperly formatted, the function automatically transmits the error code BAD_PARAMETERS to the sender
*/
void parseNextCommand(); void parseNextCommand();
public: public:
CommunicationController(const PMSVSettings &settings, MovementController &movementController); CommunicationController(const PMSVSettings &settings, MovementController &movementController);
/**
* Check for received messages and handle them.
*/
void update(); void update();
......
...@@ -2,55 +2,64 @@ ...@@ -2,55 +2,64 @@
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <utility>
enum class CommandCategory: uint8_t {
GENERAL, /**
ACTION, * Available categories for wireless commands
MOVEMENT */
enum class CommandCategory : uint8_t {
GENERAL = 0,
ACTION = 1,
MEASUREMENT = 2
}; };
enum class GeneralCommand: uint8_t { /**
SET_COMMUNICATION_ACTIVEMODE * Commands in the "General" category
*/
enum class GeneralCommand : uint8_t {
SET_COMMUNICATION_ACTIVEMODE = 0
}; };
enum class ActionCommand: uint8_t { /**
CANCEL_MOVEMENT, * Commands in the "Action" category
START_MOVE_STEPS, */
START_MOVE_CM, enum class ActionCommand : uint8_t {
START_ROTATE_DEGREES, CANCEL_MOVEMENT = 0,
SET_SPEED START_MOVE_STEPS = 1,
START_MOVE_CM = 2,
START_ROTATE_DEGREES = 3,
SET_SPEED = 4
}; };
enum class MeasurementCommand: uint8_t { /**
* Commands in the "Measurement" category
*/
enum class MeasurementCommand : uint8_t {
GET_MEASUREMENT_RAW, GET_MEASUREMENT_RAW,
GET_DISTANCE_SENSOR GET_DISTANCE_SENSOR
}; };
struct CommandData {
uint8_t category_id;
uint8_t command_id;
uint8_t min_param_length;
uint8_t max_param_length;
};
const CommandData commandDetails[] = {
{0,0, 1,1},
{1,0,0,0},
{1,1,2,3},
{1,2,2,3},
{1,3,3,3},
{1,4,1,1},
{2,0,1,2},
{2,1,1,2}
};
struct Command {
/**
* A struct containing a command received by the robot.
*/
struct Command {
/// The category id of the command (see the information sheet)
uint8_t category_id; uint8_t category_id;
/// The command id of the command (see the information sheet)
uint8_t command_id; uint8_t command_id;
/// A value for identifying a specific message.
uint8_t message_id; uint8_t message_id;
uint8_t parameters[30]; // TODO this could be handled better
size_t parameter_length; /// All parameter bytes given for this command
uint8_t parameters[5];
/// The byte count of the parameters stored in "parameters"
size_t parameter_length;
/** /**
* Create an empty message * Create an empty message
...@@ -77,9 +86,30 @@ struct Command { ...@@ -77,9 +86,30 @@ struct Command {
* @param len * @param len
* @return * @return
*/ */
static bool validate(const uint8_t * data, const uint8_t & len); static bool validate(const uint8_t *data, const uint8_t &len);
/**
* Get the minimum and maximum parameter length for a given command.
*
* @param cat The Command Category id
* @param cmd The command ID
* @return A pair of sizes, where first is the minimum size, and second is the maximum size
*/
static std::pair<uint8_t, uint8_t> getParameterLimits(CommandCategory cat, uint8_t cmd);
/**
* Get a 16 bit unsigned integer from the parameters
* @param startIndex Parameter index at which the value starts
* @param msb_first Wether the byte order is msb first (true, default) or lsbyte first(false)
* @return The requested value
*/
uint16_t get_param16(const size_t &startIndex, bool msb_first = true) const; uint16_t get_param16(const size_t &startIndex, bool msb_first = true) const;
/**
* Get a 32 bit unsigned integer from the parameters
* @param startIndex Parameter index at which the value starts
* @param msb_first Wether the byte order is msb first (true, default) or lsbyte first(false)
* @return The requested value
*/
uint32_t get_param32(const size_t &startIndex, bool msb_first = true) const; uint32_t get_param32(const size_t &startIndex, bool msb_first = true) const;
}; };
...@@ -3,19 +3,41 @@ ...@@ -3,19 +3,41 @@
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
/**
* Possible return codes for a wireless command.
*
* ReturnCodes are packed in a \refitem{ReturnCommand} and sent back to the sender.
*/
enum class ReturnCode : uint8_t { enum class ReturnCode : uint8_t {
/// The requested action was performed successfully
SUCCESS = 0, SUCCESS = 0,
/// The robot cannot handle the command because it was busy with another action
ROBOT_BUSY = 1, ROBOT_BUSY = 1,
/// Performing the requested action was impossible due to a hardware error
HARDWARE_ERROR = 2, HARDWARE_ERROR = 2,
/// (Only for movement) Performing the requested action failed because a motor was stalling
MOTOR_STALL = 3, MOTOR_STALL = 3,
/// The command received by the robot was ill-formatted
BAD_PARAMETERS = 4, BAD_PARAMETERS = 4,
/// A reading was requested for a sensor that doesn't exist
NO_SUCH_SENSOR = 5 NO_SUCH_SENSOR = 5
}; };
/**
* A command that is sent by the Robot to respond to a given \refitem{Command}
*/
struct ReturnCommand { struct ReturnCommand {
uint8_t message_id; /// The message id of the original Command. This can be used to match a returncommand to a sent command on the other side
uint8_t message_id;
/// ReturnCode for the message
ReturnCode returnCode; ReturnCode returnCode;
uint8_t data[4]; /// (Optional) the data returned from the Command
uint8_t data[4];
/// Size of the data returned
size_t data_size;
/**
* Create a ReturnCommand
*/
ReturnCommand(uint8_t messageId, ReturnCode returnCode, const uint8_t *dat); ReturnCommand(uint8_t messageId, ReturnCode returnCode, const uint8_t *dat);
}; };
...@@ -4,10 +4,24 @@ ...@@ -4,10 +4,24 @@
class MovementController; class MovementController;
class ActionCommandHandler: public CommandHandler {
/**
* Handles commands in the category \refitem{CommandCategory::ACTION}
*/
class ActionCommandHandler : public CommandHandler {
/// MovementController, used for performing movement actions
MovementController &movementController; MovementController &movementController;
public: public:
/**
* Handle an ActionCommand
* @param cmd Command to handle
* @return The result of the action. This should be sent back to the sender of the command
*/
ReturnCommand handle(const Command &cmd) override; ReturnCommand handle(const Command &cmd) override;
/**
* Construct the ActionCommandHandler
* @param movementController The robot's movementController
*/
ActionCommandHandler(MovementController &movementController); ActionCommandHandler(MovementController &movementController);
}; };
...@@ -3,7 +3,15 @@ ...@@ -3,7 +3,15 @@
#include <communication/command/Command.hpp> #include <communication/command/Command.hpp>
#include <communication/command/ReturnCommand.hpp> #include <communication/command/ReturnCommand.hpp>
/**
* Interface to handle commands in a specific category
*/
class CommandHandler { class CommandHandler {
public: public:
/**
* Handle a Command
* @param cmd Command to handle
* @return The result of the command. This should be sent back to the sender of the command
*/
virtual ReturnCommand handle(const Command &cmd) = 0; virtual ReturnCommand handle(const Command &cmd) = 0;
}; };
#pragma once #pragma once
#include <communication/handler/CommandHandler.hpp> #include <communication/handler/CommandHandler.hpp>
class GeneralCommandHandler: public CommandHandler { /**
* Handles commands in the category \refitem{CommandCategory::GENERAL}
*/
class GeneralCommandHandler : public CommandHandler {
public: public:
/**
* Handle a General Command
* @param cmd Command to handle
* @return The result of the command. This should be sent back to the sender of the command
*/
ReturnCommand handle(const Command &cmd) override; ReturnCommand handle(const Command &cmd) override;
}; };
#pragma once #pragma once
#include <communication/handler/CommandHandler.hpp> #include <communication/handler/CommandHandler.hpp>
class MeasurementCommandHandler: public CommandHandler { /**
* Handles commands in the category \refitem{CommandCategory::MEASUREMENT}
*/
class MeasurementCommandHandler : public CommandHandler {
public: public:
/**
* Handle a Measurement Command
* @param cmd Command to handle
* @return The result of the command, usually containing a measurement. This should be sent back to the sender of the command
*/
ReturnCommand handle(const Command &cmd) override; ReturnCommand handle(const Command &cmd) override;
}; };
#pragma once
#include <cstdint>
#include "AccelStepper.h"
/**
* A boundary used for a single Stepper Motor
*/
class MotorBoundary {
/// Stepper motor object that is used to move the motor
AccelStepper stepper;
public:
/**
* Create a MotorBoundary
*
* The constructor automatically creates the underlying AccelStepper object
* @param enable_pin Pin number connected to the enable pin of the stepper driver
* @param step_pin Pin number connected to the step pin of the stepper driver
* @param dir_pin Pin number connected to the dir pin of the stepper driver
* @param steps_per_mm The number of steps a motor steps fo moving a millimeter
*/
MotorBoundary(uint8_t enable_pin, uint8_t step_pin, uint8_t dir_pin, uint8_t steps_per_mm);
/**
* Start a movement of a specified amount of steps
*
* Note that the method returns before the movement is started. Movement is continued in the update() method.
* @param steps The amount of steps to move
* @return True if the starting of the movement was successful
*/
bool startMoveSteps(uint16_t steps);
/**
* Stop all movement currently being processed
*/
void halt();
/**
* Update the movement currently being processed.
* Usually steps the motor at least once
*/
void update();
};
\ No newline at end of file
#pragma once
#include <cstdint>
class MotorController {
public:
bool startMoveSteps(uint16_t steps) {
return false;
}
void halt() {
}
};
\ No newline at end of file
#pragma once #pragma once
#include <movement/MotorController.hpp> #include <movement/MotorBoundary.hpp>
#include <communication/command/ReturnCommand.hpp> #include <communication/command/ReturnCommand.hpp>
class PMSVSettings;
class MovementController { class MovementController {
MotorController leftMotor; MotorBoundary leftMotor;
MotorController rightMotor; MotorBoundary rightMotor;
public: public:
ReturnCode setSpeed(uint16_t speed); ReturnCode setSpeed(uint16_t speed);
ReturnCode setDirection(bool dir); ReturnCode setDirection(bool dir);
ReturnCode startMoveCM(uint16_t cm); ReturnCode startMoveCM(uint16_t cm);
ReturnCode startMoveSteps(uint16_t steps); ReturnCode startMoveSteps(uint16_t steps);
ReturnCode startRotateDegrees(uint16_t degrees, bool direction); ReturnCode startRotateDegrees(uint16_t degrees, bool direction);
ReturnCode halt(); ReturnCode halt();
void update(); void update();
MovementController(const PMSVSettings &pmsvSettings );
}; };
\ No newline at end of file
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
class PMSVRobot { class PMSVRobot {
MovementController movementController; MovementController movementController;
CommunicationController communicationController; CommunicationController communicationController;
PMSVSettings settings; const PMSVSettings &settings;
public: public:
PMSVRobot(PMSVSettings &settings); PMSVRobot(const PMSVSettings &settings);
void update(); void update();
}; };
......
...@@ -2,6 +2,19 @@ ...@@ -2,6 +2,19 @@
#include <RF24.h> #include <RF24.h>
struct StepperSettings {
uint8_t pin_enable;
uint8_t pin_step;
uint8_t pin_dir;
uint8_t steps_per_mm;
StepperSettings(uint8_t pinEnable, uint8_t pinStep, uint8_t pinDir, uint8_t stepsPerMm) : pin_enable(pinEnable),
pin_step(pinStep),
pin_dir(pinDir),
steps_per_mm(
stepsPerMm) {}
};
class PMSVSettings { class PMSVSettings {
public: public:
...@@ -29,11 +42,14 @@ public: ...@@ -29,11 +42,14 @@ public:
uint8_t nrf_pin_ce; uint8_t nrf_pin_ce;
uint8_t nrf_pin_csn; uint8_t nrf_pin_csn;
StepperSettings leftMotor;
StepperSettings rightMotor;
PMSVSettings(uint16_t stepsPerCm, uint16_t stepsPerDegree, bool leftMotorFwd, bool rightMotorFwd, uint16_t minSpeed, PMSVSettings(uint16_t stepsPerCm, uint16_t stepsPerDegree, bool leftMotorFwd, bool rightMotorFwd, uint16_t minSpeed,
uint16_t maxSpeed, rf24_pa_dbm_e nrfPalevel, uint8_t nrfChannel, uint64_t nrfReadingpipe, uint16_t maxSpeed, rf24_pa_dbm_e nrfPalevel, uint8_t nrfChannel, uint64_t nrfReadingpipe,
uint64_t nrfWritingpipe, bool nrfEnableDynamicpayloads, size_t nrfPacketSize, bool nrfEnableAutoack, uint64_t nrfWritingpipe, bool nrfEnableDynamicpayloads, size_t nrfPacketSize, bool nrfEnableAutoack,
uint8_t nrfPinCe, uint8_t nrfPinCsn) uint8_t nrfPinCe, uint8_t nrfPinCsn, StepperSettings leftMotor, StepperSettings rightMotor)
: steps_per_cm(stepsPerCm), : steps_per_cm(stepsPerCm),
steps_per_degree( steps_per_degree(
stepsPerDegree), stepsPerDegree),
...@@ -53,7 +69,7 @@ public: ...@@ -53,7 +69,7 @@ public:
nrfPacketSize), nrfPacketSize),
nrf_enable_autoack( nrf_enable_autoack(
nrfEnableAutoack), nrfEnableAutoack),
nrf_pin_ce(nrfPinCe), nrf_pin_csn(nrfPinCsn) {} nrf_pin_ce(nrfPinCe), nrf_pin_csn(nrfPinCsn), leftMotor(leftMotor), rightMotor(rightMotor) {}
}; };
...@@ -12,4 +12,7 @@ ...@@ -12,4 +12,7 @@
platform = atmelsam platform = atmelsam
board = due board = due
framework = arduino framework = arduino
lib_deps = tmrh20/RF24@^1.3.9 lib_deps =
tmrh20/RF24@^1.3.9
teemuatlut/TMCStepper @ ^0.7.1
pavel/AccelStepper@^1.61.0
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
CommunicationController::CommunicationController(const PMSVSettings &settings, MovementController &movementController) CommunicationController::CommunicationController(const PMSVSettings &settings, MovementController &movementController)
: nrfRadio(settings.nrf_pin_ce,