Sam

main.cpp

Committer:
s0313045
Date:
2020-09-13
Revision:
2:611a5eb132a1
Parent:
1:58d1caed28d4

File content as of revision 2:611a5eb132a1:

#include "mbed.h"

#include "ros.h"
#include <nav_msgs/Odometry.h>
#include <geometry_msgs/Twist.h>
#include <geometry_msgs/Quaternion.h>
#include <geometry_msgs/TransformStamped.h>
#include <tf/tf.h>
#include <tf/transform_broadcaster.h>

#include "actiondrv.h"

#include "millis.h"

/*
 * ActionEncoder.cpp
 *
 *  Created on: 7 Mar 2018
 *      Author: tung
 */

#include "ActionEncoder.hpp"
#include "Timer.h"



///////////////////////////
//Serial Action(D8,D2 ); // tx, rx
Serial Action(PB_6,  PB_7 );
//Serial pc(USBTX, USBRX);



union {
    uint8_t data[24];
    float val[6];
} posture;
int count=0;
int i=0;
int done=0;
float xangle=0;
float yangle=0;
float zangle=0;
float d_angle=0;
float pos_x=0;
float pos_y=0;
float angleSpeed=0;
float temp_zangle=0;
int   LastRead=0;
bool newDataArrived=false;

char buffer[8];


//Serial pc(USBTX, USBRX);
char counter = 0;
actionDrv action1(3); //1
actionDrv action2(1); //2
actionDrv action3(2); //3


int motor1 = 0;
int motor2 = 0;
int motor3 = 0;
int motor4 = 0;

float pi = 3.14159265;
double pi_div_3 = 1.04719755;
float d = 0.525;//0.43;
float wheelR = 0.0508; //4 inch wheel
float gear = 10;

Ticker motor_updater;

Ticker odom_updater;

Ticker ros_updater;


////////////////////////////////////
float now_x=0;
float now_y=0;
float now_w=0;

float target_x=0;
float target_y=0;
float target_w=0;

float tolerance_x=0.02;
float tolerance_y=0.02;
float tolerance_w=0.01;

float speed_max_x=1;
float speed_max_y=1;
float speed_max_w=1;

long odom_last_read= millis();

/////////////////////////////////////
const float RATE = 0.18;
//////////////////////////

///////////////////////////
float encoder_2_global_angle = -90;         //encoder coordinate system + 30 degree    =>  global coordinate system
//float encoder_2_global_x     =   0.34;    //encoder to center distance  in x   (tung)
//float encoder_2_global_y     =   -0.235;     //encoder to center distance  in y   (tung)


float encoder_2_global_x     = 0.33;//0.125;    //encoder to center distance  in x   (tung)
float encoder_2_global_y     = 0.24;//0.37;    //encoder to center distance  in y   (tung)
////////////////////TUNG////////////////


float transformed_real_now_x=0;
float transformed_real_now_y=0;
float transformed_real_now_w=0;


float startup_offset_x_encoder =0;
float startup_offset_y_encoder =0;
float startup_offset_w_encoder=0;



float encoder_to_center = sqrt( ( encoder_2_global_x  * encoder_2_global_x )  + ( encoder_2_global_y  *  encoder_2_global_y ) );

//#########################//
float encoder2local_angle = -90 *pi/float(180);
float encoder_position_angle =( ( 360-36.02737)  ) / float(180) * pi ;   //90 +  angle to encoder location
float r = sqrt( ( encoder_2_global_x  * encoder_2_global_x )  + ( encoder_2_global_y  *  encoder_2_global_y ) );   //encoder to center radius


void calculatePos(float _X,float _Y,float _A)
{
    float zangle  =  _A-   360 * int(_A / 360);
    float zrangle =  zangle *pi/float(180);    //degree 2 rad
    
    float tx = ( ( _X / float(1000) ) * cos( -encoder2local_angle) )  -  (  ( _Y / float(1000) )   *  sin( -encoder2local_angle) );
    float ty = ( ( _X / float(1000) ) * sin( -encoder2local_angle) )  +  (  ( _Y / float(1000) )   *  cos( -encoder2local_angle) );
    
    float s  = copysign( sqrt(  2*( r*r )  -  2*(r*r)*cos(zrangle)  )    , zrangle );
    
    float x_bias = s * cos( zrangle / 2 );
    float y_bias = s * sin( zrangle / 2 );
    
    float x_tbias = ( x_bias ) * ( cos( encoder_position_angle) )  - ( y_bias ) * ( sin( encoder_position_angle ) )    ;
    float y_tbias = ( x_bias ) * ( sin( encoder_position_angle) )  + ( y_bias ) * ( cos( encoder_position_angle ) )    ;
    
    
   transformed_real_now_x = tx + y_tbias   - startup_offset_x_encoder; //-
   transformed_real_now_y = ty - x_tbias   - startup_offset_y_encoder;
    
    //transformed_real_now_x = tx + y_tbias   - startup_offset_x_encoder;  //+
    //transformed_real_now_y = ty - x_tbias   - startup_offset_y_encoder;
    
    
    transformed_real_now_w=   _A *pi/float(180)                                                                        -  startup_offset_w_encoder;
    
    
}





///////////////////////



float x_PID_P = 0.5;
float y_PID_P = 0.5;
float w_PID_P = 1;

#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))

//////////////////////////////
void start_calculatePos(float _X,float _Y,float _A)
{
    float zangle  =  _A-   360 * int(_A / 360);
    float zrangle =  zangle *pi/float(180);    //degree 2 rad
    
    float tx = ( ( _X / float(1000) ) * cos( -encoder2local_angle) )  -  (  ( _Y / float(1000) )   *  sin( -encoder2local_angle) );
    float ty = ( ( _X / float(1000) ) * sin( -encoder2local_angle) )  +  (  ( _Y / float(1000) )   *  cos( -encoder2local_angle) );
    
    float s  = copysign( sqrt(  2*( r*r )  -  2*(r*r)*cos(zrangle)  )    , zrangle );
    
    float x_bias = s * cos( zrangle / 2 );
    float y_bias = s * sin( zrangle / 2 );
    
    float x_tbias = ( x_bias ) * ( cos( encoder_position_angle) )  - ( y_bias ) * ( sin( encoder_position_angle ) )    ;
    float y_tbias = ( x_bias ) * ( sin( encoder_position_angle) )  + ( y_bias ) * ( cos( encoder_position_angle ) )    ;
    
    
    startup_offset_x_encoder = tx + y_tbias ;  //-
    startup_offset_y_encoder = ty - x_tbias ;
    
   //startup_offset_x_encoder = tx + y_tbias ;
   //startup_offset_y_encoder = ty - x_tbias ;  //+
    
    
    startup_offset_w_encoder =  _A *pi/float(180);    //degree 2 rad
    
    
}

void ActionEncoder_init()
{
    count=0;
    i=0;
    done=0;
    xangle=0;
    yangle=0;
    zangle=0;
    d_angle=0;
    pos_x=0;
    pos_y=0;
    angleSpeed=0;
    temp_zangle=0;
    LastRead=0;
    newDataArrived=false;

}

bool readEncoder(char c)
{
    //sprintf(buffer,"%02X",c);
    //sprintf(buffer,"%X",c);
    //pc.printf(buffer);
    //pc.printf("\r\n");
    
    //sprintf(buffer,"%d",count);
    //pc.printf(buffer);
    //pc.printf("\r\n");
    switch(count) {
        case 0:
            if (c==0x0d) count++;
            else count=0;
            break;
        case 1:
            if(c==0x0a) {
                i=0;
                count++;
            } else if(c==0x0d) {}
            else count=0;
            break;
        case 2:
            posture.data[i]=c;
            i++;
            if(i>=24) {
                i=0;
                count++;
            }
            break;
        case 3:
            if(c==0x0a)count++;
            else count=0;
            break;
        case 4:
            if(c==0x0d) {
                d_angle=posture.val[0]-temp_zangle;
                if (d_angle<-180) {
                    d_angle=d_angle+360;
                } else if (d_angle>180) {
                    d_angle=d_angle-360;
                }
                
                now_w+=d_angle;
                temp_zangle=posture.val[0];
                //xangle=posture.val[1];
                //yangle=posture.val[2];
                now_x=posture.val[3];
                now_y=posture.val[4];
                //angleSpeed=posture.val[5];
                newDataArrived=true;
                
            }
            count=0;
            done=1;
            LastRead=millis();
            return true;
            //break;
        default:
            count=0;
            break;
    }
    
    return false;
}




//void inverse(float global_x_vel, float global_y_vel, float w_vel) const std_msgs::UInt16& cmd_msg
void inverse(const geometry_msgs::Twist& cmd_vel)  
{
    float global_vel_x   =  cmd_vel.linear.x;
    float global_vel_y   =  cmd_vel.linear.y;
    float w_vel          =  cmd_vel.angular.z;
    
    float local_x_vel = global_vel_x * cos( -transformed_real_now_w  )  -  global_vel_y * sin( -transformed_real_now_w ); 
    float local_y_vel = global_vel_x * sin( -transformed_real_now_w  )  +  global_vel_y * cos( -transformed_real_now_w );  //local to global transformation   (angle only)
  
    motor1  =  int(   (    (-1) * sin(pi_div_3) * local_x_vel   +  cos(pi_div_3) * local_y_vel +  d * w_vel     )  * 60 / (wheelR * 2 * pi)  * gear   );
    motor2  =  int(   (    (-1) *  local_y_vel + d * w_vel                                                      )  * 60 / (wheelR * 2 * pi)  * gear   ); 
    motor3  =  int(   (           sin(pi_div_3) * local_x_vel   +  cos(pi_div_3) * local_y_vel +  d * w_vel     )  * 60 / (wheelR * 2 * pi)  * gear   );
    
}

/////////////////////////
ros::NodeHandle nh;
ros::Subscriber<geometry_msgs::Twist> sub("cmd_vel", &inverse );

nav_msgs::Odometry odom;
geometry_msgs::TransformStamped odom_trans;
 
ros::Publisher odom_publisher("odom", &odom);
tf::TransformBroadcaster odom_broadcaster;


/////////////////////////



void motor_update()
{
    action1.SetVelocity_mod(motor1  * -1 );
    action2.SetVelocity_mod(motor2  * -1 );
    action3.SetVelocity_mod(motor3  * -1 );
    wait(0.005);
}

void ros_update()
{

odom_publisher.publish( &odom );
odom_broadcaster.sendTransform(odom_trans);


wait(0.005);
nh.spinOnce();
}


void odom_update()
{
    calculatePos(now_x,now_y,now_w);
    
    //geometry_msgs::Quaternion odom_quat = createQuaternionMsg(transformed_real_now_w );
    geometry_msgs::Quaternion odom_quat = tf::createQuaternionFromYaw(transformed_real_now_w);  // *57.2957795


    //first, we'll publish the transform over tf
    odom_trans.header.stamp = nh.now();
    odom_trans.header.frame_id = "odom";
    odom_trans.child_frame_id = "base_link";

    odom_trans.transform.translation.x = transformed_real_now_x ;
    odom_trans.transform.translation.y = transformed_real_now_y ;
    odom_trans.transform.translation.z = 0.0;
    odom_trans.transform.rotation = odom_quat;

    //send the transform
    



    //next, we'll publish the odometry message over ROS
    //nav_msgs::Odometry odom;
    odom.header.stamp = nh.now();
    odom.header.frame_id = "odom";
    odom.child_frame_id = "base_link";

    //set the position
    odom.pose.pose.position.x = transformed_real_now_x;
    odom.pose.pose.position.y = transformed_real_now_y ;
    odom.pose.pose.position.z = 0.0;
    odom.pose.pose.orientation = odom_quat;

    //set the velocity
    //odom.child_frame_id = "base_link";
    //odom.twist.twist.linear.x = vx;
    //odom.twist.twist.linear.y = vy;
    //odom.twist.twist.angular.z = vth;

    //publish the message    
    //
    
            
}
    


int main() {
    
    millisStart();
    
    
        
    Action.baud(115200);
    Action.format(8,SerialBase::None,1); 
    ActionEncoder_init();
    
    nh.initNode();
    odom_broadcaster.init(nh);
    nh.advertise(odom_publisher);
    nh.subscribe(sub);
    
    while (!nh.connected() )   {nh.spinOnce();}
        odom_trans.header.stamp = nh.now();
        odom_trans.header.frame_id = "odom";
        odom_trans.child_frame_id = "base_link";
    
        odom_trans.transform.translation.x = 0.0;
        odom_trans.transform.translation.y = 0.0 ;
        odom_trans.transform.translation.z = 0.0;
        odom_trans.transform.rotation = tf::createQuaternionFromYaw(0);
        
        odom.header.stamp = nh.now();
        odom.header.frame_id = "odom";
        odom.child_frame_id = "base_link";
    
        //set the position
        odom.pose.pose.position.x = transformed_real_now_x;
        odom.pose.pose.position.y = transformed_real_now_y ;
        odom.pose.pose.position.z = 0.0;
        odom.pose.pose.orientation = tf::createQuaternionFromYaw(0);;
        
    ros_updater.attach(&ros_update, 0.3);
    
    while(1) 
    {
        if (Action.readable())
        {
            char c = Action.getc();
            if (readEncoder(c))
            {
                //startup_offset_x_encoder = now_x/1000;
                //startup_offset_y_encoder = now_y/1000;
                //startup_offset_w_encoder = now_w/float(180)*pi;
                
                start_calculatePos(  (now_x),(now_y), now_w  );   //global
                break;
            
            }
            
        }
    }    //start first to take offset from encoder... in case already moved
    
    
    
    for( int a = 1; a < 2; a++ ){
      action1.Enable();
      action2.Enable();
      action3.Enable();
      wait(0.1);
      action1.SetOperationalMode();
      action2.SetOperationalMode();
      action3.SetOperationalMode();
      wait(0.1);
      action1.Configvelocity(100000, 100000);
      action2.Configvelocity(100000, 100000);
      action3.Configvelocity(100000, 100000);  
      wait(0.1);
   }
          
    motor_updater.attach(&motor_update, RATE);  
    //odom_updater.attach(&odom_update, RATE);
    ros_updater.attach(&ros_update, 0.5);
    

    
        
    while(1) 
    {
        if (Action.readable())
        {
            //pc.putc('a');
            char c = Action.getc();
            if(readEncoder(c)) odom_update();
        }
        
    }

       
}