RobChair.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2012, ISR University of Coimbra.
00006 *  All rights reserved.
00007 *
00008 *  Redistribution and use in source and binary forms, with or without
00009 *  modification, are permitted provided that the following conditions
00010 *  are met:
00011 *
00012 *   * Redistributions of source code must retain the above copyright
00013 *     notice, this list of conditions and the following disclaimer.
00014 *   * Redistributions in binary form must reproduce the above
00015 *     copyright notice, this list of conditions and the following
00016 *     disclaimer in the documentation and/or other materials provided
00017 *     with the distribution.
00018 *   * Neither the name of the ISR University of Coimbra nor the names of its
00019 *     contributors may be used to endorse or promote products derived
00020 *     from this software without specific prior written permission.
00021 *
00022 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 *  POSSIBILITY OF SUCH DAMAGE.
00034 *
00035 * Author: Gonçalo Cabrita on 28/05/2012
00036 *********************************************************************/
00037 
00038 #include "RobChair.h"
00039 
00040 RobChair::RobChair()
00041 {
00042     
00043 }
00044 
00045 RobChair::~RobChair()
00046 {
00047     turnTriggerOff();
00048     
00049     turnPDrivesOff();
00050     turnEncodersOff();
00051 }
00052 
00053 void RobChair::initializeRobChair(ros::Publisher * can_pub, double kp, double ki)
00054 {
00055     can_pub_ = can_pub;
00056     
00057     got_left_encoder_data_ = false;
00058     got_right_encoder_data_ = false;
00059     
00060     n_ = 0;
00061     
00062     x_ = 0.0;
00063     y_ = 0.0;
00064     yaw_ = 0.0;
00065     linear_velocity_ = 0.0;
00066     angular_velocity_ = 0.0;
00067     
00068     char data = 1;
00069     // Set the PDrives to receive commands from the Encoders
00070     sendCANFrame(RobChair::BothPDrives, RobChair::SetPDriveControlMode, &data, 1);
00071     // Set the Encoders to send commands to the PDrives
00072     sendCANFrame(RobChair::BothEncoders, RobChair::SetEncoderControlMode, &data, 1);
00073     
00074     if(kp>0.0 && ki>0.0)
00075     {
00076         setPIControlValues(RobChair::BothEncoders, kp, ki);
00077     }
00078     
00079     turnEncodersOn();
00080     turnPDrivesOn();
00081     
00082     turnTriggerOn();
00083 }
00084 
00085 void RobChair::setPIControlValues(RobChairDS destination, double kp, double ki)
00086 {
00087     // Convert the gains to integers according to the documentation
00088     long kp_int = kp*1000;
00089     long ki_int = ki*1000;
00090     
00091     char data[8];
00092     
00093     memset(data, kp_int, 4);
00094     memset(data+4, ki_int, 4);
00095     
00096     sendCANFrame(destination, RobChair::SetPIControlValues, data, 8);
00097 }
00098 
00099 void RobChair::setVelocities(double linear_velocity, double angular_velocity)
00100 {
00101     double delta_v = (ROBCHAIR_AXLE_LENGTH * angular_velocity)/2.0;
00102     
00103     // Left wheel velocity
00104     double left_velocity = ((linear_velocity - delta_v)/ROBCHAIR_WHEEL_RADIUS) * ROBCHAIR_K;
00105     // Right wheel velocity
00106         double right_velocity = ((linear_velocity + delta_v)/ROBCHAIR_WHEEL_RADIUS) * ROBCHAIR_K;
00107     
00108     char data[2];
00109     
00110     data[0] = static_cast<int>(left_velocity) & 0x0FF;
00111     data[1] = (static_cast<int>(left_velocity) >> 8) & 0x0FF;
00112     // Reference velocity must be sent at N=3
00113     sendCANFrame(RobChair::LeftEncoder, RobChair::SetVelocityValue, data, 2, 3);
00114     
00115     data[0] = static_cast<int>(right_velocity) & 0x0FF;
00116     data[1] = (static_cast<int>(right_velocity) >> 8) & 0x0FF;
00117     // Reference velocity must be sent at N=3
00118     sendCANFrame(RobChair::RightEncoder, RobChair::SetVelocityValue, data, 2, 3);
00119 }
00120 
00121 void RobChair::decodeEncoderData(RobChairDS encoder, const can_msgs::CANFrame::ConstPtr& msg)
00122 {
00123     double temp_wheel_position;
00124         double temp_wheel_velocity;
00125     
00126     temp_wheel_position = (static_cast<int>(msg->data[3]) << 24) + (static_cast<int>(msg->data[2]) << 16) + (static_cast<int>(msg->data[1]) << 8) + static_cast<int>(msg->data[0]);
00127         temp_wheel_velocity = (static_cast<int>(msg->data[5]) << 8) + static_cast<int>(msg->data[4]);
00128     
00129     temp_wheel_position = static_cast<double>(temp_wheel_position)*(ROBCHAIR_CONTROL_PERIOD/ROBCHAIR_K);
00130         temp_wheel_velocity = static_cast<double>(temp_wheel_velocity)*(1/ROBCHAIR_K);
00131                              
00132     if(encoder == RobChair::LeftEncoder)
00133     {
00134         last_left_wheel_position_ = left_wheel_position_;
00135         left_wheel_position_ = temp_wheel_position * ROBCHAIR_WHEEL_RADIUS;
00136         left_wheel_velocity_ = temp_wheel_velocity * ROBCHAIR_WHEEL_RADIUS;
00137         got_left_encoder_data_ = true;
00138     }
00139     else if(encoder == RobChair::RightEncoder)
00140     {
00141         last_right_wheel_position_ = right_wheel_position_;
00142         right_wheel_position_ = temp_wheel_position * ROBCHAIR_WHEEL_RADIUS;
00143         right_wheel_velocity_ = temp_wheel_velocity * ROBCHAIR_WHEEL_RADIUS;
00144         got_right_encoder_data_ = true;
00145     }
00146     
00147     // If we got both encoders data lets process it!
00148     if(got_left_encoder_data_ && got_left_encoder_data_)
00149     {
00150         double delta_phi_left = left_wheel_position_ - last_left_wheel_position_;
00151         double delta_phi_right = right_wheel_position_ - last_right_wheel_position_;
00152         
00153         double delta_s = (delta_phi_right + delta_phi_left)/2;
00154         double delta_theta = (delta_phi_right - delta_phi_left)/ROBCHAIR_AXLE_LENGTH;
00155 
00156         double half_theta = limitAngle(yaw_ + delta_theta/2);
00157         
00158         x_ += delta_s * cos(half_theta);
00159         y_ += delta_s * sin(half_theta);
00160         yaw_ = limitAngle(yaw_ + delta_theta);
00161         
00162         linear_velocity_ = (right_wheel_velocity_ + left_wheel_velocity_)/2;
00163         angular_velocity_ = (right_wheel_velocity_ - left_wheel_velocity_)/ROBCHAIR_AXLE_LENGTH;
00164         
00165         got_left_encoder_data_ = false;
00166         got_right_encoder_data_ = false;
00167     }
00168 }
00169 
00170 void RobChair::sendCANFrame(RobChairDS destination, char function, char * data, int data_count, char n)
00171 {
00172     can_msgs::CANFrame frame;
00173     
00174     frame.stamp = ros::Time::now();
00175     
00176     frame.id = destination << 7 + RobChair::PC << 4 + function;
00177     frame.data.resize(data_count);
00178     for(int i=0 ; i<data_count ; i++)
00179     {
00180         frame.data[i] = data[i];
00181     }
00182     
00183     // If a valid trigger time slot is provided...
00184     if(n>0 && n<=5)
00185     {
00186         // Wait for it!
00187         while(n_!=n)
00188         {
00189             ros::Duration(ROBCHAIR_CONTROL_PERIOD/5.0/10.0).sleep();
00190         }
00191     }
00192     
00193     can_pub_->publish(frame);
00194 }
00195 
00196 void RobChair::receivedCANFrame(const can_msgs::CANFrame::ConstPtr& msg)
00197 {
00198     ROS_INFO("RobChair - %s - Got a message!", __FUNCTION__);
00199     
00200     // First lets see what we got here...
00201     char function = msg->id & ROBCHAIR_FUNCTION_MASK;
00202     char source = msg->id & ROBCHAIR_SOURCE_MASK;
00203     char destination = msg->id & ROBCHAIR_DESTINATION_MASK;
00204     
00205     ROS_INFO("RobChair - %s - D:%d S:%d F:%d", __FUNCTION__, destination, source, function);
00206 
00207     // If the message is not meant for us drop it
00208     if(destination != RobChair::PC) return;
00209     
00210     // Now lets check who sent it...
00211     switch(source)
00212     {
00213         case RobChair::RightEncoder:
00214             if(function == RobChair::DataFromEncoder)
00215             {
00216                 decodeEncoderData(RobChair::RightEncoder, msg);
00217             }
00218             break;
00219         
00220         case RobChair::LeftEncoder:
00221             if(function == RobChair::DataFromEncoder)
00222             {
00223                 decodeEncoderData(RobChair::LeftEncoder, msg);
00224             }
00225             break;
00226             
00227         case RobChair::SyncMCU:
00228             if(function == RobChair::SyncronizeAllNodes)
00229             {
00230                 n_ = msg->data[0];
00231             }
00232             break;
00233             
00234         default:
00235             ROS_ERROR("RobChair - %s - Got CAN frame from an unknown source: %d", __FUNCTION__, source);
00236             break;
00237     }
00238 }
00239 
00240 double RobChair::limitAngle(double angle)
00241 {
00242     double correct_angle;
00243     
00244     if(angle > M_PI)
00245     {
00246         correct_angle = angle - 2 * M_PI;
00247     }
00248     else if(angle < - M_PI)
00249     {
00250         correct_angle = angle + 2 * M_PI;
00251     }
00252     else
00253     {
00254         correct_angle = angle;
00255     }
00256     
00257     return correct_angle;
00258 }
00259 
00260 
00261 // EOF


robchair_driver
Author(s): Gonçalo Cabrita
autogenerated on Mon Jan 6 2014 11:26:14