Professional Documents
Culture Documents
Team 6
Team 6
#include <chai3d.h>
#define MESH_SCALE 0.001
#define PI 3.14159265359
// definitions
#define ZMIN_WS 0.8
#define ZMIN_INIT 0.5
#define Z_OFFSET 0.3
#define RMAX
0.8
#define RMIN
0.5
#define C
0.9
#define REDUCE_CYL_OUT 0.1
#define REDUCE_CYL_IN 0.11
// trajectory generation
#define VMAX 1
#define AMAX 7
#define JMAX 7
#define VMAX_Z 0.05
#define ERROR_ZONE 0.2
// Optitrack offsets
#define X_OPTITRACK_OFFSET -0.84
#define Y_OPTITRACK_OFFSET 0.95
#define Z_OPTITRACK_OFFSET 0.05
#define LANDING_THRESHOLD 0.1
// Module level variables
scl::SDatabase *db;
// Position states
// default: followKeys
// KEY 1: followKeys
// KEY 2: followOptitrack
// KEY 3: followNothing
typedef enum { FOLLOW_KEYS, FOLLOW_OPTITRACK, FOLLOW_NOTHING} PositionState;
typedef enum { ORIENTATION_UP, ORIENTATION_DOWN} OrientationState;
bool sendRobot = false; // variable to know if we are sending commands to robot
// function Prototypes
//void updateOptitrack();
PositionState checkPositionKeys(void);
OrientationState checkOrientationKey(void);
void checkWSBoundary(Eigen::Vector3d& x_goal);
void toJointLimits(Eigen::VectorXd &q);
/** A sample application to demonstrate how to set up your own task in SCL...
int main(int argc, char** argv)
{
std::cout << "\n***********************************************\n";
std::cout << "Standard Control Library Tutorial : Custom Tasks";
std::cout << "\n***********************************************\n";
*/
bool flag;
bool zmqIntialized = false;
scl::SRobotParsed rds;
//Robot data structure.... //node names, actuators,
joint limits, damping..
scl::SGraphicsParsed rgr; //Robot graphics data structure...
scl::SGcModel rgcm; //Robot data structure with dynamic quantities... //M, q, dq,
transformation matrices, every important things
scl::SRobotIO rio;
//I/O data structure
scl::CGraphicsChai rchai; //Chai interface (updates graphics rendering tree
etc.)
scl::CDynamicsScl dyn_scl; //Robot kinematics and dynamics computation object...
compute Transformation matrices, Jacobians
scl::CDynamicsTao dyn_tao; //Robot physics integrator.. compute Position and
Velocity
scl::CParserScl p;
//This time, we'll parse the tree from a file...
scl::SControllerMultiTask rctr_ds; //A multi-task controller data structure
//list all tasks
scl::CControllerMultiTask rctr;
//A multi-task controller
std::vector<scl::STaskBase*> rtasks;
//A set of executable tasks
std::vector<scl::SNonControlTaskBase*> rtasks_nc; //A set of non-control tasks
std::vector<scl::sString2> ctrl_params;
//Used to parse extra xml tags
scl::STaskOpPos* rtask_hand; //Will need to set hand desired positions etc.
sutil::CSystemClock::start(); //Start the clock
/******************************Set up Dynamic Type for our new
Task************************************/
scl_app::STaskOrientation *rtask_Ori; //A pointer for our new task
flag = scl_app::registerType_TaskOrientation(); //Let SCL parse our new task
type..
if (false == flag) {
std::cout << "\n Could not register custom task type\n";
return 1;
}
// NOTE : The task hand name should match the XML Config file.
std::string Ori_parent_link("Ori");
/******************************Set up Shared Memory
(Database)************************************/
// This will us share data between the GUI and the controller
db = scl::CDatabase::getData();
if (NULL == db) {
std::cout << "\n ERROR : Could not initialize global data storage";
return 1;
}
scl_util::getCurrentDir(db->cwd_);
db->dir_specs_ = db->cwd_ + std::string("./");
/******************************Load Robot
Specification************************************/
//We will use a slightly more complex xml spec than the first few tutorials
const std::string fname("./iiwaCfg.xml");
flag = p.readRobotFromFile(fname, "./", "iiwaBot", rds);
flag = flag && rgcm.init(rds);
//Simple way to set up dynamic tree...
flag = flag && dyn_tao.init(rds);
//Set up integrator object
flag = flag && dyn_scl.init(rds);
//Set up kinematics and dynamics object
flag = flag && rio.init(rds);
//Set up the I/O data structure
int dof = 3;
// Initialize variables
RML = new ReflexxesAPI(dof, dt);
IP = new RMLPositionInputParameters(dof);
OP = new RMLPositionOutputParameters(dof);
// Set initial values for Traj Gen
// Initial position for Traj Gen, should be the same as initial position of end
effector
bool selectVec[3] = {true, true, true};
for (int i = 0; i < dof; i++) {
//IP->CurrentPositionVector->VecData[i] = plateInitPos[i];
IP->CurrentPositionVector->VecData[i] = rtask_hand->x_[i];
IP->CurrentVelocityVector->VecData[i] = 0;
IP->CurrentAccelerationVector->VecData[i] = 0;
IP->MaxVelocityVector->VecData[i] = VMAX;
IP->MaxAccelerationVector->VecData[i] = AMAX;
IP->MaxJerkVector->VecData[i] = JMAX;
IP->SelectionVector->VecData[i] = selectVec[i];
//setting OP pos for initialization purpose; don't have to set vel and acc coz
initial value is 0
//OP->NewPositionVector->VecData[i] = plateInitPos[i];
OP->NewPositionVector->VecData[i] = rtask_hand->x_[i];
}
/*********************************** Threading Starts Below
*************************************/
omp_set_num_threads(2);
int thread_id;
double tstart, tcurr, tCelebrate;
flag = false;
int dflag = 0;
bool celebrateFlag;
double cosineParam, controlPos;
//std::cout << rio.sensors_.q_.transpose() << std::endl;
// PRINT STATEMENTS FOR USER
std::cout << "Press 1 to FOLLOW KEYS" << std::endl
<< "Press 2 to FOLLOW OPTITRACK" << std::endl
<< "Press 3 to HOLD POSITION (FOLLOW NOTHING)" << std::endl
<< std::endl
<< "Press 0 to FLIP ORIENTATION" << std::endl
<< std::endl
<< "Press 5 to SEND TO ROBOT" << std::endl;
#pragma omp parallel private(thread_id)
{
thread_id = omp_get_thread_num();
if (thread_id == 1) {
tstart = sutil::CSystemClock::getSysTime();
iter = 0;
while (true == scl_chai_glut_interface::CChaiGlobals::getData()>chai_glut_running) {
tcurr = sutil::CSystemClock::getSysTime();
/*************************************** start of POSITION stuff
*****************************/
// READ ALL KEY STROKES for position command
static Eigen::Vector3d x_goal_temp;
// temp vector to start
x_goal_temp
Eigen::Vector3d x_goal_debug;
static bool lastYPlus = db->s_gui_.ui_flag_[8];
bool currYPlus = db->s_gui_.ui_flag_[8];
Eigen::Vector3d endEffectorPos = rtask_hand->x_;
Eigen::Vector3d endEffectorErr;
bool inErrorZone = false;
double cur_x, cur_y, cur_z;
// read key strokes to determine states
PositionState X_GOAL_STATE= checkPositionKeys();
// swtich statement to determine x_goal_temp
switch(X_GOAL_STATE)
{
case FOLLOW_KEYS:
// assign UI points to x_goal_temp
for (int i = 0; i < 3; i++)
{
x_goal_temp[i] = db->s_gui_.ui_point_[0][i];
}
break;
case FOLLOW_OPTITRACK:
// assign Optitrack position to x_goal_temp
if (iter%5==0) // update every 5 ms (each control loop is 1ms)
UpdateOptitrack();
// Updates optitrack to
update new target position
double* currentPosition;
currentPosition = getPositionOpti();
// get current Position of
target
// If we are potentially allowed to celebrate
if(celebrateFlag){
tCelebrate = tcurr - tstart;
if(tCelebrate>5){
//amp = (endEffectorPos[2] - ZMIN_WS)/2;
//avg = (endEffectorPos[2] + ZMIN_WS)/2;
cosineParam = 1*(tCelebrate);
//controlPos = (amp)*cos(cosineParam) + avg;
controlPos = (0.2)*cos(cosineParam) + 1.0;
//std::cout << endEffectorPos[0] << " " << endEffectorPos[1] << "
" << endEffectorPos[2] << " " << std::endl;
inErrorZone = false;
// Put copter in
x_goal_temp[2] =
x_goal_temp[0] =
x_goal_temp[1] =
restart position
controlPos;
0.068;
0.50;
}
}
else {
tstart = tcurr;
tCelebrate = 0;
}
case FOLLOW_NOTHING:
// do nothing
// static x_goal_temp will remain the same as previous iteration
break;
default:
;
}
// make sure x_goal_temp is within workspace boundaries
checkWSBoundary(x_goal_temp);
// DEBUG: print x_goal_temp
// if (iter % 20 == 0)
//
std::cout << "x_goal_temp: " << x_goal_temp.transpose() << std::endl;
// assign position parameters for trajectory generation
for (int i = 0; i < 3; i++)
{
IP->TargetPositionVector->VecData[i] = x_goal_temp[i];
}
*IP->CurrentPositionVector = *OP->NewPositionVector;
*IP->CurrentVelocityVector = *OP->NewVelocityVector;
*IP->CurrentAccelerationVector = *OP->NewAccelerationVector;
// Calling the Reflexxes OTG algorithm
int ResultValue = RML->RMLPosition(*IP, OP, Flags);
if (ResultValue < 0) {
printf("An error occurred (%d).\n", ResultValue);
break;
}
if (!inErrorZone)
{
//Set goal position
for (int i = 0; i < dof; i++) {
x_goal_temp[i] = OP->NewPositionVector->VecData[i];
}
}
// write x_goal_temp
rtask_hand->x_goal_ = x_goal_temp;
if (iter%5 == 0)
{
static zmqpp::context context;
static zmqpp::socket pub(context, zmqpp::socket_type::publish);
if (!zmqIntialized)
{
// Need to pair this with the endpoint port in ROS code
pub.bind("tcp://*:3883");
zmqIntialized = true;
}
// TODO: Is data lock needed here?
else
{
zmqpp::message msg;
Eigen::VectorXd q;
//q = rctr_ds.getGeneralizedCoordinates();
q = rio.sensors_.q_;
toJointLimits(q);
//std::cout << q.transpose() << std::endl;
msg << std::to_string(q[0]) + " " +
std::to_string(q[1]) + " " +
std::to_string(q[2]) + " " +
std::to_string(-q[3]) + " " +
std::to_string(q[4]) + " " +
std::to_string(q[5]) + " " +
std::to_string(q[6]);
// joint 3 is inverted
pub.send(msg);
//std::cout << "Sending" << q.transpose() << "\n";
}
}
}
else
sendRobot = false;
/* ------------------------------------------- UI Update ---------------------------------------------------*/
// Update the position of the target GUI element
sphere_pos[0] = db->s_gui_.ui_point_[0](0);
sphere_pos[1] = db->s_gui_.ui_point_[0](1);
sphere_pos[2] = db->s_gui_.ui_point_[0](2);
// Update graphics
target->setLocalPos(sphere_pos[0], sphere_pos[1], sphere_pos[2]);
//use current hand pos to render plate. <-- use this so the plate does not
drift
plate->graphics_obj_->setLocalPos(rtask_hand->x_[0],
rtask_hand->x_[1], rtask_hand->x_[2] - 0.02);
// use current hand orientation to render plate <-- use this so the drawing
reflects current end-effector orientation.
chai3d::cMatrix3d plateCurrOri(
rtask_Ori->Ori(0, 1),
rtask_Ori->Ori(1, 1),
rtask_Ori->Ori(2, 1),
<----No set global
tstart;
std::cout << "\n\tSimulated time = " << static_cast<double>(iter) * dt;
std::cout << "\n\nExecuted Successfully";
std::cout << "\n**********************************\n" << std::flush;
return 0;
}
// Function checkPositionKeys()
// Description: function to read Keys 1,2,3. If a key is pressed, it will return
// the corresponding state. If no key is pressed, it will return its previous
state (through
// the use of the static variable ReturnState)
//
//
//
//
default: followKeys
KEY 1: followKeys
KEY 2: followOptitrack
KEY 3: followNothing
PositionState
{
static bool
static bool
static bool
checkPositionKeys(void)
LastFollowKeysFlag;
LastFollowOptitrackFlag;
LastFollowNothingFlag;
}
return ReturnState;
}
// Function: checkOrientationKEY()
// Description: checkts keystrock for change in Orientation Key
// returns OrientationState for whether to flip orientation up or down
// USES KEY 0
OrientationState checkOrientationKey(void)
{
static bool LastOrientationFlag;
bool CurOrientationFlag = db->s_gui_.ui_flag_[0];
// Initialize to ORIENTATION_DOWN
static OrientationState ReturnState = ORIENTATION_DOWN;
// If FollowKeys Flag has changed
if (CurOrientationFlag != LastOrientationFlag)
{
if (ReturnState == ORIENTATION_DOWN)
ReturnState = ORIENTATION_UP;
else
ReturnState = ORIENTATION_DOWN;
LastOrientationFlag = CurOrientationFlag;
}
return ReturnState;
}
// new spherical WS Boundary
void checkWSBoundary(Eigen::Vector3d& x_goal)
{
const double A = RMAX;
const double B = RMAX;
double x = x_goal[0];
double y = x_goal[1];
double z = x_goal[2] - Z_OFFSET;
int Quadrant = 0;
if (x >= 0 && y >= 0)
Quadrant = 1;
else if (x < 0 && y >= 0)
Quadrant = 2;
else if (x < 0 && y < 0)
Quadrant = 3;
else if (x >= 0 && y < 0)
Quadrant = 4;
// calculate phi = (acos(z/r))
// since phi is always between 0 and 180 we don't need to check quadrants
double phi = acos(z/(sqrt(x*x+y*y+z*z)));
// determine x & y goal from trig
switch (Quadrant)
{
case 1:
x = RMIN*cos(theta)*sin(phi);
y = RMIN*sin(theta)*sin(phi);
z = RMIN*cos(phi);
break;
case 2:
x = -RMIN*cos(theta)*sin(phi);
y = -RMIN*sin(theta)*sin(phi);
z = RMIN*cos(phi);
break;
case 3:
x = -RMIN*cos(theta)*sin(phi);
y = -RMIN*sin(theta)*sin(phi);
z = RMIN*cos(phi);
break;
case 4:
x = RMIN*cos(theta)*sin(phi);
y = RMIN*sin(theta)*sin(phi);
z = RMIN*cos(phi);
break;
default:
;
}
}
// CHECK Z minimum BOUNDS
z += Z_OFFSET;
if (sendRobot)
{
if (z<ZMIN_WS)
z = ZMIN_WS;
}
else
{
if (z < ZMIN_INIT)
z = ZMIN_INIT;
}
// reassign x to x_goal
x_goal[0] = x;
x_goal[1] = y;
x_goal[2] = z;
} // end CheckWSBoundary
// more WS
void toJointLimits(Eigen::VectorXd &q) {
q = 180*q/PI;
if(q[0] < -160) {
q[0] = -160;
} else if (q[0]>160){
q[0] = 160;
}
if(q[1] < -110) {
q[1] = -110;
} else if (q[1]>110){
q[1] = 110;
}
if(q[2] < -160) {
q[2] = -160;
} else if (q[2]>160){
q[2] = 160;
}
if(q[3] < -110) {
q[3] = -110;
} else if (q[3]>110){
q[3] = 110;
}
if(q[4] < -160) {
q[4] = -160;
} else if (q[4]>160){
q[4] = 160;
}
if(q[5] < -110) {
q[5] = -110;
} else if (q[5]>110){
q[5] = 110;
}
if(q[6] < -165) {
q[6] = -165;
} else if (q[6]>165){
q[6] = 165;
}
q = PI*q/180;
}