Difference between revisions of "5. Joint PD Control Without Hand Library"
Line 13: | Line 13: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | #include " | + | #include "myAHController.h" |
− | #include " | + | #include "myAHControllerCmd.h" |
− | + | ||
− | + | ||
− | + | myAHController::myAHController(rDC rdc) | |
− | + | ||
:rControlAlgorithmEx(rdc) | :rControlAlgorithmEx(rdc) | ||
− | |||
− | |||
− | |||
− | |||
− | |||
{ | { | ||
+ | // initialize all the class member variables | ||
} | } | ||
− | + | ||
− | + | myAHController::~myAHController() | |
{ | { | ||
− | |||
− | |||
} | } | ||
− | + | ||
− | + | void myAHController::init(int mode) | |
− | void | + | |
{ | { | ||
+ | // create hand and find devices | ||
+ | // arrange joint devices function will be called here | ||
+ | // set degrees of freedom | ||
+ | // make sure all vectors are the correct size and | ||
+ | // set all of the components to zero before computing | ||
+ | } | ||
− | + | void myAHController::_arrangeJointDevices() | |
− | + | { | |
− | + | // find and store all motors and encoders | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | void myAHController::update(const rTime& t) | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | void | + | |
{ | { | ||
− | + | // Evokes _readDevices(), _estimate(), _reflect(), | |
− | + | // _compute(), _writeDevices() in turn by default. | |
− | + | ||
− | + | ||
} | } | ||
− | + | ||
− | void | + | void myAHController::_readDevices() |
{ | { | ||
− | // | + | // read sensors |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | void | + | void myAHController::_writeDevices() |
{ | { | ||
− | // | + | // write to actuators |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | + | ||
− | void | + | void myAHController::_compute(const double& t) |
{ | { | ||
− | // | + | // Computes control inputs |
} | } | ||
− | + | ||
− | int | + | int myAHController::command(const short& cmd, const int& arg) |
{ | { | ||
// Handles user-defined commands according to cmd. | // Handles user-defined commands according to cmd. | ||
// Further information can be retrieved from the second argument. | // Further information can be retrieved from the second argument. | ||
− | + | ||
// The variable cmd will be received from Allegro Application Studio | // The variable cmd will be received from Allegro Application Studio | ||
// and will be used to envoke hand actions | // and will be used to envoke hand actions | ||
return 0; | return 0; | ||
} | } | ||
− | + | ||
rControlAlgorithm* CreateControlAlgorithm(rDC& rdc) | rControlAlgorithm* CreateControlAlgorithm(rDC& rdc) | ||
{ | { | ||
− | return new | + | return new myAHController(rdc); |
} | } | ||
Line 166: | Line 85: | ||
<div class="mw-collapsible-content"> | <div class="mw-collapsible-content"> | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | |||
− | |||
+ | #ifndef __MY_AH_CONTROLLER_H__ | ||
+ | #define __MY_AH_CONTROLLER_H__ | ||
+ | |||
#include <list> | #include <list> | ||
#include "rControlAlgorithm/rControlAlgorithm.h" | #include "rControlAlgorithm/rControlAlgorithm.h" | ||
#include "BHand/BHand.h" | #include "BHand/BHand.h" | ||
− | + | ||
− | + | // myAHController inherited from algorithm interface class | |
− | + | class REXPORT myAHController : public rControlAlgorithmEx | |
− | // | + | |
− | class REXPORT | + | |
{ | { | ||
public: | public: | ||
− | + | myAHController(rDC rdc); | |
− | ~ | + | ~myAHController(); |
− | + | ||
virtual void init(int mode = 0); | virtual void init(int mode = 0); | ||
virtual void update(const rTime& t); | virtual void update(const rTime& t); | ||
virtual int command(const short& cmd, const int& arg = 0); | virtual int command(const short& cmd, const int& arg = 0); | ||
− | + | ||
private: | private: | ||
virtual void _readDevices(); | virtual void _readDevices(); | ||
virtual void _writeDevices(); | virtual void _writeDevices(); | ||
− | + | ||
virtual void _compute(const rTime& t); | virtual void _compute(const rTime& t); | ||
− | + | ||
void _arrangeJointDevices(); | void _arrangeJointDevices(); | ||
− | + | ||
− | + | ||
private: | private: | ||
− | + | ||
− | + | // algorithm variables go here | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
}; | }; | ||
− | + | ||
#endif | #endif | ||
Line 228: | Line 130: | ||
<div class="mw-collapsible-content"> | <div class="mw-collapsible-content"> | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | |||
− | |||
+ | #ifndef __MY_AH_CONTROLLER_CMD_H__ | ||
+ | #define __MY_AH_CONTROLLER_CMD_H__ | ||
+ | |||
#include "rCommand/rCmdManipulator.h" | #include "rCommand/rCmdManipulator.h" | ||
− | + | ||
// These commands will be fed into command() | // These commands will be fed into command() | ||
// and can be used to envoke certain actions | // and can be used to envoke certain actions | ||
Line 241: | Line 144: | ||
#define BH_HOME (RCMD_GO_HOME) | #define BH_HOME (RCMD_GO_HOME) | ||
// #define BH_ONE (RCMD_USER + 1) | // #define BH_ONE (RCMD_USER + 1) | ||
− | + | ||
#endif | #endif | ||
Revision as of 15:57, 30 April 2015
In the past 4 tutorials, we learned how to control the Allegro Hand using the included grasping and motions library. In this tutorials, we will take a step back and control the hand at a lower level. We will go over basic filtering of the encoder data and PD position control of the joints.
For this lesson, we must roll back our controller code to the point before we implemented any code to move the hand joints. It may be a better idea to start a new project with the following code. Remember, you configure the project according to the DLL project properties from tutorial 1. Your code should reflect the code developed in the three steps of tutorial 2:
myAHController.cpp
#include "myAHController.h" #include "myAHControllerCmd.h" myAHController::myAHController(rDC rdc) :rControlAlgorithmEx(rdc) { // initialize all the class member variables } myAHController::~myAHController() { } void myAHController::init(int mode) { // create hand and find devices // arrange joint devices function will be called here // set degrees of freedom // make sure all vectors are the correct size and // set all of the components to zero before computing } void myAHController::_arrangeJointDevices() { // find and store all motors and encoders } void myAHController::update(const rTime& t) { // Evokes _readDevices(), _estimate(), _reflect(), // _compute(), _writeDevices() in turn by default. } void myAHController::_readDevices() { // read sensors } void myAHController::_writeDevices() { // write to actuators } void myAHController::_compute(const double& t) { // Computes control inputs } int myAHController::command(const short& cmd, const int& arg) { // Handles user-defined commands according to cmd. // Further information can be retrieved from the second argument. // The variable cmd will be received from Allegro Application Studio // and will be used to envoke hand actions return 0; } rControlAlgorithm* CreateControlAlgorithm(rDC& rdc) { return new myAHController(rdc); }
myAHController.h
#ifndef __MY_AH_CONTROLLER_H__ #define __MY_AH_CONTROLLER_H__ #include <list> #include "rControlAlgorithm/rControlAlgorithm.h" #include "BHand/BHand.h" // myAHController inherited from algorithm interface class class REXPORT myAHController : public rControlAlgorithmEx { public: myAHController(rDC rdc); ~myAHController(); virtual void init(int mode = 0); virtual void update(const rTime& t); virtual int command(const short& cmd, const int& arg = 0); private: virtual void _readDevices(); virtual void _writeDevices(); virtual void _compute(const rTime& t); void _arrangeJointDevices(); private: // algorithm variables go here }; #endif
myAHControllerCmd.h
#ifndef __MY_AH_CONTROLLER_CMD_H__ #define __MY_AH_CONTROLLER_CMD_H__ #include "rCommand/rCmdManipulator.h" // These commands will be fed into command() // and can be used to envoke certain actions // by the robot. Allegro Application Studio // will use these to interface with the // cotroller plug-in. #define BH_NONE (RCMD_USER + 0) #define BH_HOME (RCMD_GO_HOME) // #define BH_ONE (RCMD_USER + 1) #endif
Contents |
Check the code
Let's quickly compile the code above to make sure we copied everything correctly. It should compile with no errors.
Next, open up AHAS via your virtual Allegro Hand shortcut. None of the buttons should work anymore but you should see the command prompt indication that all motors and encoders have been found. These are all we need!
Reading and Writing
We have two functions, _readDevices() and _writeDevices(), that are called every control period. For the Allegro Hand controller, this means that the encoder values are accessed and motor commands are calculated and written at 333Hz, or once every 0.003 seconds.
When _readDevices() accessed the encoder data, it saves it to the array _q[]" which has 16 floating point entries (once for each joint). The joint positions in _q are in radians.
Similarly, when writing a torque command to the motors, "_writeDevices()" accesses the 16-long floating-point array _torque[]'. The torque values are in the unit Newton-meters.
Alike _readDevices() and "_writeDevices()", the function '_compute() is also called every control iteration. This is where we will implement are controller code, or the computation of motor torque based on joint positions.
Remember: The 16 joint torque commands and joint positions are stored in float arrays with 16 entries each and indexed as follows:
Finger | Joint | Index |
1 | 1 | 0 |
1 | 2 | 1 |
1 | 3 | 2 |
1 | 4 | 3 |
2 | 1 | 4 |
2 | 2 | 5 |
2 | 3 | 6 |
2 | 4 | 7 |
3 | 1 | 8 |
3 | 2 | 9 |
3 | 3 | 10 |
3 | 4 | 11 |
4 | 1 | 12 |
4 | 2 | 13 |
4 | 3 | 14 |
4 | 4 | 15 |
Let's add a bit of code to apply a small torque to all four (4) joints on the index finger and subsequently read the joint position of each and print it to the command window.
control_AllegroHand.cpp
void control_AllegroHand::_compute(const double& t) { // Joints 0, 1, 2 and 3 are commanded at 0.1 N.m for (int i=0; i<4; i++) { _torque[i] = 0.1; } // Joint positions 0, 1, 2 and 3 are printed for (int i=0; i<4; i++) { printf("%i: %f\t",i,_q[i]); } printf("\n"); // next line }
That was easy! We can now design any controller with a position input and a torque output.
PD Control
One of the simplest and most widely used control algorithms, Proportional-Derivative (PD) control can be easily implemented to control the position of a robotic joint.
To use PD control, we need to calculate the error between the joint's set, or desired, position and the joint's current position. For each joint, this error value and a gain value will comprise the proportional controller. Along with the current error, we will also calculate the error's rate of change from time-step to time-step. This will be calculated using the difference between the current and previous error values divided by the time-step.
Whos here now: Members 0 Guests 0 Bots & Crawlers 1 |