bool update_trajectory(double traj_clock, trajectory_msgs::JointTrajectory trajectory, Vectorq7x1 qvec_prev, int &isegment, Vectorq7x1 &qvec_new) {
    trajectory_msgs::JointTrajectoryPoint trajectory_point_from, trajectory_point_to;
    int njnts = qvec_prev.size();
    Vectorq7x1 qvec, qvec_to, delta_qvec, dqvec;
    int nsegs = trajectory.points.size() - 1;
    double t_subgoal;
    //cout<<"traj_clock = "<<traj_clock<<endl;
    if (isegment < nsegs) {
        trajectory_point_to = trajectory.points[isegment + 1];
        t_subgoal = trajectory_point_to.time_from_start.toSec();
        //cout<<"iseg = "<<isegment<<"; t_subgoal = "<<t_subgoal<<endl;
    } else {
        cout << "reached end of last segment" << endl;
        trajectory_point_to = trajectory.points[nsegs];
        t_subgoal = trajectory_point_to.time_from_start.toSec();
        for (int i = 0; i < 7; i++) {
            qvec_new[i] = trajectory_point_to.positions[i];
        }
        cout << "final time: " << t_subgoal << endl;
        return false;
    }

    //cout<<"iseg = "<<isegment<<"; t_subgoal = "<<t_subgoal<<endl;
    while ((t_subgoal < traj_clock)&&(isegment < nsegs)) {
        //cout<<"loop: iseg = "<<isegment<<"; t_subgoal = "<<t_subgoal<<endl;
        isegment++;
        if (isegment > nsegs - 1) {
            //last point
            trajectory_point_to = trajectory.points[nsegs];
            for (int i = 0; i < 7; i++) {
                qvec_new[i] = trajectory_point_to.positions[i];
            }
            cout << "iseg>nsegs" << endl;
            return false;
        }

        trajectory_point_to = trajectory.points[isegment + 1];
        t_subgoal = trajectory_point_to.time_from_start.toSec();
    }
    //cout<<"t_subgoal = "<<t_subgoal<<endl;
    //here if have a valid segment:
    for (int i = 0; i < 7; i++) {
        qvec_to[i] = trajectory_point_to.positions[i];
    }
    delta_qvec = qvec_to - qvec_prev; //this far to go until next node;
    double delta_time = t_subgoal - traj_clock;
    if (delta_time < dt_traj) delta_time = dt_traj;
    dqvec = delta_qvec * dt_traj / delta_time;
    qvec_new = qvec_prev + dqvec;
    return true;
}
void inPointCallback(const geometry_msgs::Point& pt_msg) {
    Eigen::Affine3d des_gripper1_wrt_base;

    g_des_point(0) = pt_msg.x;
    g_des_point(1) = pt_msg.y;
    g_des_point(2) = pt_msg.z;
    cout << "received des point = " << g_des_point.transpose() << endl;
    g_des_gripper_affine1.translation() = g_des_point;
    //convert this to base coords:
    g_des_gripper1_wrt_base = g_affine_lcamera_to_psm_one.inverse() * g_des_gripper_affine1;
    //try computing IK:
    if (g_ik_solver.ik_solve(g_des_gripper1_wrt_base)) {
        ROS_INFO("found IK soln");
        g_got_new_pose = true;
        g_q_vec1_start = g_q_vec1_goal;
        g_q_vec1_goal = g_ik_solver.get_soln();
        cout << g_q_vec1_goal.transpose() << endl;
        g_trajectory_point1 = g_trajectory_point2; //former goal is new start

        for (int i = 0; i < 6; i++) {
            g_trajectory_point2.positions[i] = g_q_vec1_goal[i]; //leave psm2 angles alone; just update psm1 goal angles
        }
        //gripper_affines_wrt_camera.push_back(affine_gripper_frame_wrt_camera_frame_);
        //    des_trajectory.joint_names.push_back("right_s0"); //yada-yada should fill in names
        g_des_trajectory.header.stamp = ros::Time::now();

        g_des_trajectory.points[0] = g_des_trajectory.points[1]; //former goal is new start
        g_des_trajectory.points[1] = g_trajectory_point2;



        // copy traj to goal:
        g_goal.trajectory = g_des_trajectory;
    } else {
        ROS_WARN("NO IK SOLN FOUND");
    }

}
int main(int argc, char** argv) {
    ros::init(argc, argv, "test_cart_path_planner_lib");
    ros::NodeHandle nh; //standard ros node handle   

    ROS_INFO("instantiating an ArmMotionInterface: ");
    ArmMotionInterface armMotionInterface(&nh);


    //can do this, if needed: A = cartTrajPlanner.get_fk_Affine_from_qvec(Vectorq7x1 q_vec)    

    cout << "instantiating a traj streamer" << endl; // enter 1:";
    //cin>>ans;
    // let the streamer be owned by "main"
    Baxter_traj_streamer baxter_traj_streamer(&nh); //instantiate a Baxter_traj_streamer object and pass in pointer to nodehandle for constructor to use  
    // warm up the joint-state callbacks;
    cout << "warming up callbacks..." << endl;
    for (int i = 0; i < 100; i++) {
        ros::spinOnce();
        //cout<<"spin "<<i<<endl;
        ros::Duration(0.01).sleep();
    }
    cout << "getting current right-arm pose:" << endl;
    g_q_vec_right_arm[0] = 1000;
    while (fabs(g_q_vec_right_arm[0]) > 3) { // keep trying until see viable value populated by fnc
        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm();
        ros::spinOnce();
        ros::Duration(0.01).sleep();
    }
    cout << "r_arm state:" << g_q_vec_right_arm.transpose() << endl;

    //let's leave this in main:

    ROS_INFO("instantiating an action client of trajActionServer");
    actionlib::SimpleActionClient<baxter_traj_streamer::trajAction> traj_streamer_action_client("trajActionServer", true);

    // attempt to connect to the server:
    ROS_INFO("waiting for server trajActionServer: ");
    bool server_exists = false;
    while ((!server_exists)&&(ros::ok())) {
        server_exists = traj_streamer_action_client.waitForServer(ros::Duration(5.0)); // wait for up to 5 seconds
        ros::spinOnce();
        ros::Duration(0.5).sleep();
        ROS_INFO("retrying...");
    }

    // something odd in above: does not seem to wait for 5 seconds, but returns rapidly if server not running
    // if (!server_exists) {
    //     ROS_WARN("could not connect to server; will wait forever");
    //    return 0; // bail out; optionally, could print a warning message and retry
    //}
    //server_exists = action_client.waitForServer(); //wait forever 

    ROS_INFO("connected to action server"); // if here, then we connected to the server;    


    bool unpackok;
    Eigen::Vector3d delta_p;
    bool is_valid;
    bool finished_before_timeout;
    baxter_traj_streamer::trajGoal goal;
    Vectorq7x1 q_vec_goal_vq7; //goal pose in joint space, expressed as a 7x1 vector
    moveit_msgs::DisplayTrajectory display_trajectory;
    ros::Publisher  display_traj_pub = nh.advertise<moveit_msgs::DisplayTrajectory>("/preview_traj", 1, true);

    // start servicing requests:
    while (ros::ok()) {
        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm(); // update the current sensed arm angles
        //decide if should start processing a new request:
        if (armMotionInterface.newRqst()&&!armMotionInterface.isBusy()) {
            armMotionInterface.setNewRqst(false); //g_received_new_request_=false; // reset trigger to receive a new request
            armMotionInterface.setIsBusy(true); //g_busy_working_on_a_request_= true; // begin processing new request
        }
        if (armMotionInterface.isBusy()) {
            switch (armMotionInterface.get_cmd_mode()) {
                case ARM_TEST_MODE:
                    ROS_INFO("responding to request TEST_MODE: ");
                    cout << "unpacking q_vec_start from request message..." << endl;
                    unpackok = armMotionInterface.unpack_qstart();
                    if (unpackok) {
                        cout << "start qvec rqst: " << armMotionInterface.get_start_qvec().transpose() << endl;
                    }
                    unpackok = armMotionInterface.unpack_qend();
                    if (unpackok) {
                        cout << "end qvec rqst: " << armMotionInterface.get_end_qvec().transpose() << endl;
                    }
                    //reply w/ populating q_vec_start in response:

                    armMotionInterface.setIsBusy(false);
                    break;
                    
                case ARM_PLAN_JSPACE_PATH_CURRENT_TO_QGOAL: 
                    ROS_INFO("case ARM_PLAN_JSPACE_PATH_CURRENT_TO_QGOAL");
                    //get the start q_vec = current arm pose:
                    cout << "getting current right-arm pose:" << endl;
                    g_q_vec_right_arm[0] = 1000;  //Vectorq7x1 g_q_vec_right_arm;
                    while (fabs(g_q_vec_right_arm[0]) > 3) { // keep trying until see viable value populated by fnc
                        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm();
                        ros::spinOnce();
                        ros::Duration(0.01).sleep();
                    }
                    //get the goal q_vec, per request message:
                    armMotionInterface.unpack_qend();
                    q_vec_goal_vq7= armMotionInterface.get_end_qvec(); //need to convert from VectorXd to Vectorq7x1
                    is_valid = armMotionInterface.plan_jspace_path_qstart_to_qend(g_q_vec_right_arm,q_vec_goal_vq7);
                    if (is_valid) ROS_INFO("computed valid path");
                    else ROS_INFO("no valid path found");
                    armMotionInterface.setIsBusy(false);
                    break;                    
                

                case ARM_PLAN_PATH_CURRENT_TO_PRE_POSE:
                    ROS_INFO("responding to request PLAN_PATH_CURRENT_TO_PRE_POSE");
                    armMotionInterface.plan_path_to_predefined_pre_pose();
                    armMotionInterface.setIsBusy(false);
                    break;

                case ARM_PLAN_PATH_CURRENT_TO_GOAL_POSE:
                    cout << "getting current right-arm pose:" << endl;
                    g_q_vec_right_arm[0] = 1000;
                    while (fabs(g_q_vec_right_arm[0]) > 3) { // keep trying until see viable value populated by fnc
                        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm();
                        ros::spinOnce();
                        ros::Duration(0.01).sleep();
                    }
                    //armMotionInterface.unpack_qstart(); // fills in q_vec_start_rqst_--no...use current arm pose
                    armMotionInterface.unpack_goal_pose(); //fills in a_flange_end_;  should check return status   
                    //    bool plan_path_qstart_to_Agoal(Vectorq7x1 q_start); // provide q_start; assumes use of a_flange_end_ and fills in g_optimal_path 
                    is_valid = armMotionInterface.plan_path_qstart_to_Agoal(g_q_vec_right_arm);
                    if (is_valid) ROS_INFO("computed valid path");
                    else ROS_INFO("no valid path found");
                    armMotionInterface.setIsBusy(false);
                    break;
                    
                case ARM_DISPLAY_TRAJECTORY:
                    cout << "getting current joint states:" << endl;
                    g_q_vec_right_arm[0] = 1000;
                    while (fabs(g_q_vec_right_arm[0]) > 3) { // keep trying until see viable value populated by fnc
                        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm();
                        ros::spinOnce();
                        ros::Duration(0.01).sleep();
                    } 
                    //if here, then joint_states_ is valid
                    //populate the moveit message to preview the trajectory plan;
                    //display_trajectory.model_id = "robot_description"; // not sure what goes here;  "baxter"??
                    //declare joint_states_ as start state of display
                    display_trajectory.trajectory_start.joint_state = baxter_traj_streamer.get_joint_states(); // get the joint states from Baxter; 
                    baxter_traj_streamer.stuff_trajectory(g_optimal_path, g_des_trajectory);//convert planned path to trajectory
                    display_trajectory.trajectory.resize(1); //display only 1 trajectory
                    display_trajectory.trajectory[0].joint_trajectory = g_des_trajectory; //the one we care about
                    display_traj_pub.publish(display_trajectory); // and publish this to topic "/preview_traj"
                    armMotionInterface.setIsBusy(false);
                    break;

                case ARM_DESCEND_20CM:
                    ROS_INFO("responding to request DESCEND_20CM");
                    delta_p << 0, 0, -0.2; //specify delta-p for a 20cm descent
                    // find a joint-space path to do this, holding R fixed

                    cout << "getting current right-arm pose:" << endl;
                    g_q_vec_right_arm[0] = 1000;
                    while (fabs(g_q_vec_right_arm[0]) > 3) { // keep trying until see viable value populated by fnc
                        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm();
                        ros::spinOnce();
                        ros::Duration(0.01).sleep();
                    }

                    is_valid = armMotionInterface.plan_cartesian_delta_p(g_q_vec_right_arm, delta_p);
                    armMotionInterface.setPathValid(is_valid);
                    armMotionInterface.incrementPathID();
                    armMotionInterface.setIsBusy(false);
                    break;
                case ARM_DEPART_20CM:
                    ROS_INFO("responding to request ARM_DEPART_20CM");
                    delta_p << 0, 0, 0.2; //specify delta-p for a 20cm descent
                    // find a joint-space path to do this, holding R fixed

                    cout << "getting current right-arm pose:" << endl;
                    g_q_vec_right_arm[0] = 1000;
                    while (fabs(g_q_vec_right_arm[0]) > 3) { // keep trying until see viable value populated by fnc
                        g_q_vec_right_arm = baxter_traj_streamer.get_qvec_right_arm();
                        ros::spinOnce();
                        ros::Duration(0.01).sleep();
                    }

                    is_valid = armMotionInterface.plan_cartesian_delta_p(g_q_vec_right_arm, delta_p);
                    armMotionInterface.setPathValid(is_valid);
                    armMotionInterface.incrementPathID();
                    armMotionInterface.setIsBusy(false);
                    break;

                    //case DEPART_20CM:
                    //case CART_MOVE_DELTA_P: unpack_delta_p()...
                    //case PLAN_PATH_QSTART_TO_ADES:
                    //case PLAN_PATH_QSTART_TO_QGOAL:
                    //case PLAN_PATH_ASTART_TO_QGOAL:

                case ARM_EXECUTE_PLANNED_PATH: //assumes there is a valid planned path in g_optimal_path
                    ROS_INFO("responding to request EXECUTE_PLANNED_PATH");
                    if (armMotionInterface.getPathValid()) {
                        // convert path to a trajectory:
                        baxter_traj_streamer.stuff_trajectory(g_optimal_path, g_des_trajectory); //convert from vector of 7dof poses to trajectory message   
                        goal.trajectory = g_des_trajectory;
                        ROS_INFO("sending action request to traj streamer node");
                        traj_streamer_action_client.sendGoal(goal, &doneCb); // we could also name additional callback functions here, if desired
                        //    action_client.sendGoal(goal, &doneCb, &activeCb, &feedbackCb); //e.g., like this

                        finished_before_timeout = traj_streamer_action_client.waitForResult(ros::Duration(20.0));

                        if (!finished_before_timeout) {
                            ROS_WARN("EXECUTE_PLANNED_PATH: giving up waiting on result");
                            // should set status in service request here...
                        } else {
                            ROS_INFO("finished before timeout");
                            // should set status in service request here...
                        }
                    } else {
                        ROS_WARN("requested move without valid path! doing nothing");
                    }
                    armMotionInterface.setIsBusy(false);
                    break;
                default:
                    ROS_WARN("this command mode is not defined: %d", armMotionInterface.get_cmd_mode());
                    //clean up/terminate:
                    armMotionInterface.setIsBusy(false);
            }
        }
        ros::spinOnce();
        //cout<<"main loop..."<<endl;
        ros::Duration(0.1).sleep(); //don't consume much cpu time if not actively working on a command
    }

    return 0;
}
int do_inits() {
    Eigen::Matrix3d R;
    Eigen::Vector3d nvec, tvec, bvec, tip_pos;
    bvec << 0, 0, 1; //default for testing: gripper points "down"
    nvec << 1, 0, 0;
    tvec = bvec.cross(nvec);
    R.col(0) = nvec;
    R.col(1) = tvec;
    R.col(2) = bvec;
    g_des_gripper_affine1.linear() = R;
    tip_pos << -0.15, -0.03, 0.07;
    g_des_gripper_affine1.translation() = tip_pos; //will change this, but start w/ something legal

    //hard-coded camera-to-base transform, useful for simple testing/debugging
    g_affine_lcamera_to_psm_one.translation() << -0.155, -0.03265, 0.0;
    nvec << -1, 0, 0;
    tvec << 0, 1, 0;
    bvec << 0, 0, -1;
    //Eigen::Matrix3d R;
    R.col(0) = nvec;
    R.col(1) = tvec;
    R.col(2) = bvec;
    g_affine_lcamera_to_psm_one.linear() = R;

    g_q_vec1_start.resize(7);
    g_q_vec1_goal.resize(7);
    g_q_vec2_start.resize(7);
    g_q_vec2_goal.resize(7);

    g_des_gripper1_wrt_base = g_affine_lcamera_to_psm_one.inverse() * g_des_gripper_affine1;
    g_ik_solver.ik_solve(g_des_gripper1_wrt_base); // compute IK:
    g_q_vec1_goal = g_ik_solver.get_soln();
    g_q_vec1_start = g_q_vec1_goal;
    g_q_vec2_start << 0, 0, 0, 0, 0, 0, 0; //just put gripper 2 at home position
    g_q_vec2_goal << 0, 0, 0, 0, 0, 0, 0;
    //repackage q's into a trajectory;
    //populate a goal message for action server; 
    // initialize with 2 poses that are identical
    g_trajectory_point1.positions.clear();
    g_trajectory_point2.positions.clear();
    //resize these:
    for (int i=0;i<14;i++)  {
        g_trajectory_point1.positions.push_back(0.0); 
        g_trajectory_point2.positions.push_back(0.0); 
    }
        
    for (int i = 0; i < 7; i++) { 
        g_trajectory_point1.positions[i] = g_q_vec1_start[i];
        g_trajectory_point1.positions[i + 7] = g_q_vec2_start[i];
        //should fix up jaw-opening values...do this later
    }

    g_trajectory_point1.time_from_start = ros::Duration(0.0);
    g_trajectory_point2.time_from_start = ros::Duration(2.0);


    g_des_trajectory.points.clear(); // can clear components, but not entire trajectory_msgs
    g_des_trajectory.joint_names.clear();
    //    des_trajectory.joint_names.push_back("right_s0"); //yada-yada should fill in names
    g_des_trajectory.header.stamp = ros::Time::now();

    g_des_trajectory.points.push_back(g_trajectory_point1); // first point of the trajectory 
    g_des_trajectory.points.push_back(g_trajectory_point2);

    // copy traj to goal:
    g_goal.trajectory = g_des_trajectory;
    g_got_new_pose = true; //send robot to start pose
    
     ROS_INFO("getting transforms from camera to PSMs");
    tf::TransformListener tfListener;
    tf::StampedTransform tfResult_one, tfResult_two;
    bool tferr = true;
    int ntries = 0;
    ROS_INFO("waiting for tf between base and right_hand...");
    while (tferr) {
        if (ntries > 5) break; //give up and accept default after this many tries
        tferr = false;
        try {
            //The direction of the transform returned will be from the target_frame to the source_frame. 
            //Which if applied to data, will transform data in the source_frame into the target_frame. See tf/CoordinateFrameConventions#Transform_Direction
            tfListener.lookupTransform("left_camera_optical_frame", "one_psm_base_link", ros::Time(0), tfResult_one);
            //tfListener.lookupTransform("left_camera_optical_frame", "two_psm_base_link", ros::Time(0), tfResult_two);
        } catch (tf::TransformException &exception) {
            ROS_WARN("%s", exception.what());
            tferr = true;
            ros::Duration(0.5).sleep(); // sleep for half a second
            ros::spinOnce();
            ntries++;
        }
    }
    //default transform: need to match this up to camera calibration!
    if (tferr) {
        g_affine_lcamera_to_psm_one.translation() << -0.155, -0.03265, 0.0;
        Eigen::Vector3d nvec, tvec, bvec;
        nvec << -1, 0, 0;
        tvec << 0, 1, 0;
        bvec << 0, 0, -1;
        Eigen::Matrix3d R;
        R.col(0) = nvec;
        R.col(1) = tvec;
        R.col(2) = bvec;
        g_affine_lcamera_to_psm_one.linear() = R;
        g_affine_lcamera_to_psm_one.linear() = R;
        g_affine_lcamera_to_psm_one.translation() << 0.145, -0.03265, 0.0;
        ROS_WARN("using default transform");
    } else {

        ROS_INFO("tf is good");

        //affine_lcamera_to_psm_one is the position/orientation of psm1 base frame w/rt left camera link frame
        // need to extend this to camera optical frame
        g_affine_lcamera_to_psm_one = transformTFToEigen(tfResult_one);
        //affine_lcamera_to_psm_two = transformTFToEigen(tfResult_two);
    }
    ROS_INFO("transform from left camera to psm one:");
    cout << g_affine_lcamera_to_psm_one.linear() << endl;
    cout << g_affine_lcamera_to_psm_one.translation().transpose() << endl;
    //ROS_INFO("transform from left camera to psm two:");
    //cout << affine_lcamera_to_psm_two.linear() << endl;
    //cout << affine_lcamera_to_psm_two.translation().transpose() << endl;    
    
    
    ROS_INFO("done w/ inits");

    return 0;
    
}
int main(int argc, char **argv) {
    ros::init(argc, argv, "baxter_kinematics_test_main");
    ros::NodeHandle nh;
    ros::Subscriber joint_state_sub = nh.subscribe("robot/joint_states", 1, jointStatesCb);
    q_vec_right_arm<< 0,0,0,0,0,0,0;
    q_in << 0,0,0,0,0,0,0;
    //q_in << 0.1, 0.2, 0.3, 0.4, 0.5, 0.6;
    tf::TransformListener tfListener;
    tf::StampedTransform tfResult;
    
// set up and initialize joint publishers:
  ros::Publisher pub_right, pub_left; //Create a 'publisher' object
  baxter_core_msgs::JointCommand right_cmd,left_cmd;  // define instances of these message types, to control arms
  left_cmd.mode = 1; // set the command modes to "position"
  right_cmd.mode = 1;

// define the joint angles 0-6 to be right arm, from shoulder out to wrist;
  right_cmd.names.push_back("right_s0");
  right_cmd.names.push_back("right_s1");
  right_cmd.names.push_back("right_e0");
  right_cmd.names.push_back("right_e1");
  right_cmd.names.push_back("right_w0");
  right_cmd.names.push_back("right_w1");
  right_cmd.names.push_back("right_w2");
// same order for left arm
  left_cmd.names.push_back("left_s0");
  left_cmd.names.push_back("left_s1");
  left_cmd.names.push_back("left_e0");
  left_cmd.names.push_back("left_e1");
  left_cmd.names.push_back("left_w0");
  left_cmd.names.push_back("left_w1");
  left_cmd.names.push_back("left_w2");

  // do push-backs to establish desired vector size with valid joint angles
  for (int i=0;i<7;i++) {
     right_cmd.command.push_back(0.0); // start commanding 0 angle for right-arm 7 joints
     left_cmd.command.push_back(0.0); // start commanding 0 angle for left-arm 7 joints
   }

//set up the publisher to publish to /robot/limb/right/joint_command with a queue size of 1
  pub_right = nh.advertise<baxter_core_msgs::JointCommand>("/robot/limb/right/joint_command", 1); 
//do same for left limb:
  pub_left = nh.advertise<baxter_core_msgs::JointCommand>("/robot/limb/left/joint_command", 1);    
    
   bool tferr=true;
    ROS_INFO("waiting for tf between base and right_hand...");
    while (tferr) {
        tferr=false;
        try {
                //try to lookup transform from target frame "odom" to source frame "map"
            //The direction of the transform returned will be from the target_frame to the source_frame. 
             //Which if applied to data, will transform data in the source_frame into the target_frame. See tf/CoordinateFrameConventions#Transform_Direction
                tfListener.lookupTransform("right_arm_mount","right_hand", ros::Time(0), tfResult);
            } catch(tf::TransformException &exception) {
                ROS_ERROR("%s", exception.what());
                tferr=true;
                ros::Duration(0.5).sleep(); // sleep for half a second
                ros::spinOnce();                
            }   
    }
    ROS_INFO("tf is good");
    //right_upper_shoulder is located at bottom of first shoulder jnt
    // from now on, tfListener will keep track of transforms    
    tfListener.lookupTransform("right_arm_mount", "right_lower_shoulder", ros::Time(0), tfResult);
    tf::Vector3 pos = tfResult.getOrigin();
    ROS_INFO("shoulder x,y, z = %f, %f, %f",pos[0],pos[1],pos[2]);

    tfListener.lookupTransform("right_arm_mount","right_lower_elbow", ros::Time(0), tfResult);
    pos = tfResult.getOrigin();
    ROS_INFO("elbow x,y, z = %f, %f, %f",pos[0],pos[1],pos[2]);
    tfListener.lookupTransform("right_arm_mount","right_lower_forearm",  ros::Time(0), tfResult);
    pos = tfResult.getOrigin();
    ROS_INFO("wrist x,y, z = %f, %f, %f",pos[0],pos[1],pos[2]);     
    tfListener.lookupTransform("right_arm_mount","right_hand",  ros::Time(0), tfResult);
    pos = tfResult.getOrigin();
    ROS_INFO("hand x,y, z = %f, %f, %f",pos[0],pos[1],pos[2]);   
    
    Baxter_fwd_solver baxter_fwd_solver; //instantiate a forward-kinematics solver
    Baxter_IK_solver baxter_IK_solver;  // instantiate an IK solver
    
    
    //Baxter_IK_solver ik_solver;
    Eigen::Affine3d A_fwd_DH;
    Eigen::Matrix4d A_wrist,A_elbow,A_shoulder,A_flange;    
    Eigen::Matrix3d R_hand;
    std::cout << "==== Test for Baxter kinematics solver ====" << std::endl;

    Eigen::Matrix3d R_flange_wrt_right_arm_mount;
    Eigen::Vector3d wrist_pt_wrt_right_arm_frame1;
    Eigen::Vector3d w_err;
    int ans;
    int nsolns;
    bool valid;
    Vectorq7x1 q_vec_display,q_precise,q_soln_w_wrist_precise;
    std::vector<Vectorq7x1> q_solns;   
  // try new fnc:     
    //int Baxter_IK_solver::ik_solve_approx_wrt_torso_given_qs0(Eigen::Affine3d const& desired_hand_pose_wrt_torso,double q_s0, std::vector<Vectorq7x1> &q_solns) {
        q_snapshot = q_vec_right_arm;
        cout<<"qvec right arm: "<<endl;
        cout<< q_snapshot.transpose() <<endl;
        // from this test pose, establish a viable hand frame:
    Eigen::Affine3d Affine_flange_wrt_torso = baxter_fwd_solver.fwd_kin_flange_wrt_torso_solve(q_snapshot); //fwd_kin_solve
    
    Eigen::Affine3d Affine_flange_wrt_arm_mount = 
            baxter_fwd_solver.transform_affine_from_torso_frame_to_arm_mount_frame(Affine_flange_wrt_torso);
    R_flange_wrt_right_arm_mount = Affine_flange_wrt_arm_mount.linear();
    nsolns = baxter_IK_solver.ik_solve_approx_wrt_torso_given_qs0(Affine_flange_wrt_torso,q_snapshot[0],q_solns);
    cout<<"ik_solve_approx_wrt_torso_given_qs0 found nsolns = "<<nsolns<<endl;
    for (int i=0;i<nsolns;i++) {
        cout<<q_solns[i].transpose()<<endl;
    }
    Vectorq7x1 q_approx;
    Vectorq7x1 q_7dof_precise;
    cout<<"result of new fnc improve_7dof_soln:"<<endl;    
    for (int i=0;i<nsolns;i++) {
        q_approx = q_solns[i];
        valid = baxter_IK_solver.improve_7dof_soln(Affine_flange_wrt_arm_mount, q_approx, q_7dof_precise); 
        cout<<q_7dof_precise.transpose()<<endl;        
    }    
    //q_precise = q_solns[0]; // pick one and improve on it;
    // need to do this for each soln, e.g. 4 solns per q_s0;
    //double w_err_norm= baxter_IK_solver.precise_soln_q123(Affine_flange_wrt_arm_mount,q_solns[0], q_precise);
    //cout<<"q123 soln after Jacobian iterations: "<<endl;
    //cout<<q_precise.transpose()<<endl;
    //correspondingly, do this for each of the above improved q123 solns   
    //baxter_IK_solver.update_spherical_wrist(q_precise,R_flange_wrt_right_arm_mount, q_soln_w_wrist_precise);
    //cout<<"soln after update wrist: "<<endl;
    //cout<<q_soln_w_wrist_precise.transpose()<<endl;
    
    //valid = baxter_IK_solver.improve_7dof_soln(Affine_flange_wrt_arm_mount, q_approx, q_7dof_precise); 
    //cout<<"result of new fnc improve_7dof_soln:"<<endl;
    //cout<<q_7dof_precise.transpose()<<endl;
    //baxter_IK_solver.solve_spherical_wrist(q_precise,R_flange_wrt_right_arm_mount, q_soln_w_wrist_precise); 
    //cout<<"solns after Jacobian iterations: "<<endl;
    //for (int i=0;i<q_solns_w_wrist_precise.size();i++) {
    //    cout<<q_solns_w_wrist_precise[i].transpose()<<endl;
    //}    
    
    
    
    while (ros::ok()) 
    {
        cout<<"enter 1 to initiate: "; //pause here to allow user to move joint angles to desired test pose
        cin>>ans;
        for (int i=0;i<10;i++) { // spin to get current joint angles
            ros::spinOnce();
            ros::Duration(0.1).sleep(); //sleep for 2 seconds
        }
        q_snapshot = q_vec_right_arm;
        cout<<"qvec right arm: "<<endl;
        cout<< q_snapshot.transpose() <<endl;
        // from this test pose, establish a viable hand frame:
        A_fwd_DH = baxter_fwd_solver.fwd_kin_flange_wrt_r_arm_mount_solve(q_snapshot); //fwd_kin_solve

        cout<<"TRYING NEW FNC ik_solve_approx"<<endl;
        nsolns = baxter_IK_solver.ik_solve_approx(A_fwd_DH,q_solns);
        cout<<"num solns: "<<nsolns<<endl;
        cout<<"commanding these solutions..."<<endl;

 
       for (int isoln=0; isoln<nsolns; isoln++) {
               q_vec_display= q_solns[isoln];
               for (int j=0;j<7;j++) {
                    right_cmd.command[j] = q_vec_display[j];    
                }

            pub_right.publish(right_cmd); //publish jnt cmds to right arm
            cout<<"soln: "<<q_vec_display.transpose()<<endl;
            ros::Duration(2).sleep(); //sleep for 2 seconds
            ros::spinOnce();            
        }
    
    ros::Duration(2).sleep(); //sleep for 2 seconds
    ros::spinOnce();

    }
    return 0;
}