Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MantisInfo.h

Go to the documentation of this file.
00001 #ifndef INCLUDED_MantisInfo_h
00002 #define INCLUDED_MantisInfo_h
00003 
00004 #include <cmath>
00005 #include <stdlib.h>
00006 #include "CommonInfo.h"
00007 using namespace RobotInfo;
00008 
00009 // see http://tekkotsu.org/porting.html#configuration for more information on TGT_HAS_* flags
00010 #if defined(TGT_MANTIS)
00011 #  define TGT_IS_MANTIS
00012 #  define TGT_HAS_CAMERA 1
00013 #  define TGT_HAS_LEGS 6
00014 #  define TGT_HAS_LEDS 16
00015 #  define TGT_HAS_HEAD 1
00016 #  define TGT_HAS_POWER_STATUS
00017 #  define TGT_HAS_KINECT 1
00018 #  define TGT_HAS_GRIPPER 2
00019 #endif
00020 
00021 //! Contains information about a Mantis robot, such as number of joints, LEDs, etc.
00022 namespace MantisInfo {
00023 
00024   // *******************************
00025   //       ROBOT CONFIGURATION
00026   // *******************************
00027 
00028   extern const char* const TargetName; //!< the name of the model, to be used for logging and remote GUIs
00029 
00030   const unsigned int FrameTime=32;        //!< time between frames in the motion system (milliseconds)
00031   const unsigned int NumFrames=1;        //!< the number of frames per buffer (don't forget also double buffered)
00032   const unsigned int SoundBufferTime=32; //!< the number of milliseconds per sound buffer... I'm not sure if this can be changed
00033   
00034   //!@name Output Types Information
00035   const unsigned NumWheels      =  0;
00036 
00037   const unsigned FingerJointsPerArm = 0;
00038   const unsigned JointsPerArm   =  0;
00039   const unsigned NumArms        =  0;
00040   const unsigned NumArmJoints   =  JointsPerArm*NumArms;
00041 
00042   const unsigned JointsPerFrLeg  =  7; //!< The number of joints per front leg
00043   const unsigned JointsPerPosLeg =  4; //!< The number of joints per posterior leg (middle and the back legs)
00044   const unsigned NumFrLegs       =  2; //!< The number of front legs
00045   const unsigned NumGrippers     =  NumFrLegs; //!< The number of grippers 
00046   const unsigned NumPosLegs      =  4; //!< The number of posterior legs
00047   const unsigned NumLegs         =  NumFrLegs + NumPosLegs; //!< The number of legs
00048   const unsigned NumFrLegJoints  =  JointsPerFrLeg*NumFrLegs; //!< the TOTAL number of joints in FRONT legs
00049   const unsigned NumPosLegJoints =  JointsPerPosLeg*NumPosLegs; //!< the TOTAL number of joints in POSTERIOR legs
00050   const unsigned NumLegJoints    =  NumFrLegJoints + NumPosLegJoints; //!< the TOTAL number of joints on ALL legs
00051 
00052   const unsigned NumHeadJoints   =  3; //!< The number of joints in the pantiltroll
00053   const unsigned NumTailJoints   =  0; //!< The number of joints assigned to the tail
00054   const unsigned NumMouthJoints  =  0; //!< the number of joints that control the mouth
00055   const unsigned NumEarJoints    =  0; //!< The number of joints which control the ears (NOT per ear, is total)
00056   const unsigned NumButtons      =  3; //!< the number of buttons that are available
00057   const unsigned NumSensors      =  11; //!< the number of sensors available
00058   const unsigned NumFacePanelLEDs = 0; //!< The number of face panel LEDs
00059 
00060   const unsigned NumPIDJoints   = NumArmJoints + 1 + NumLegJoints + NumHeadJoints + NumTailJoints + NumMouthJoints; //!< servo pins (also includes the thorax joint)
00061   const unsigned NumLEDs        = NumPIDJoints; //!< There's an LED on every dynamixel, but can't see most of them, so save some computational resources and only expose the visible ones
00062   
00063   const unsigned NumOutputs     = NumWheels + NumPIDJoints + NumLEDs; //!< the total number of outputs
00064   const unsigned NumReferenceFrames = NumOutputs + NumLegs + NumArms + NumGrippers + 1 + 1; //!< for the feet, grippers, base and camera
00065 
00066   using namespace Camera75DOF;
00067   
00068   const float BallOfFootRadius = 0; //!< radius of the ball of the foot
00069   const unsigned FrontLegExtra = JointsPerFrLeg -1; //!< The number of extra joints in front legs
00070 
00071   // *******************************
00072   //         OUTPUT OFFSETS
00073   // *******************************
00074 
00075   //!Corresponds to entries in ERS7Info::PrimitiveName, defined at the end of this file
00076   //!@name Output Offsets
00077 
00078   const unsigned PIDJointOffset = 0; //!< The beginning of the PID Joints
00079   const unsigned LegOffset  = PIDJointOffset; //!< the offset of the beginning of the regular leg joints (after the 1 rotator joint for the right front leg):  #NumLegs of #JointsPerLeg each, in #LegOrder_t order; see #LegOffset_t
00080   const unsigned ThoraxJointOffset = LegOffset+NumLegJoints;  //!< the offset of the beginning of the head joints, add #TPROffset_t to get specific joint
00081   const unsigned HeadOffset = ThoraxJointOffset + 1;
00082 
00083   const unsigned LEDOffset  = PIDJointOffset + NumPIDJoints; //!< the offset of LEDs in WorldState::outputs and MotionCommand functions, see LedOffset_t for specific offsets
00084   
00085   const unsigned BaseFrameOffset = NumOutputs; //!< Use with kinematics to refer to base reference frame
00086   const unsigned FootFrameOffset    = BaseFrameOffset + 1;//!< Use with kinematics to refer to feet reference frames (add appropriate LegOrder_t to specify which paw)
00087   const unsigned GripperFrameOffset = FootFrameOffset+NumLegs; //!< Use with kinematics to refer to gripper reference frame
00088   const unsigned CameraFrameOffset  = GripperFrameOffset + NumGrippers; //!< Use with kinematics to refer to camera reference frame
00089     
00090   //! the ordering of legs
00091   enum LegOrder_t {
00092     LFrLegOrder = 0,    //!< left front leg
00093     RFrLegOrder,        //!< right front leg
00094     LMdLegOrder,        //!< left middle leg
00095     RMdLegOrder,        //!< right middle leg
00096     LBkLegOrder,        //!< left back leg
00097     RBkLegOrder         //!< right back leg
00098   };
00099 
00100   //! The offsets within the Front Legs. Note that the ordering matches the actual physical ordering of joints on the appendage
00101   enum FrLegOffset_t {
00102     FrSweepOffset = 0,      //!< moves leg forward or backward along body
00103     FrElevatorOffset,       //!< moves leg toward or away from body
00104     FrTwist1Offset,         //!< moves the first twist joint
00105     FrElbowOffset,          //!< rotation of elbow joint
00106     FrTwist2Offset,         
00107     FrWristOffset,          //!< moves wrist
00108     FrGripperOffset
00109   };
00110   
00111 
00112   //! The offsets within the Posterior Legs. Note that the ordering matches the actual physical ordering of joints on the appendage
00113   enum PosLegOffset_t {
00114     PosSweepOffset = 0, //!< moves leg forward or backward along body
00115     PosRotorOffset,         //!< rotates leg
00116     PosElevatorOffset,  //!< moves leg toward or away from body
00117     PosKneeOffset   //!< moves knee
00118   };
00119   
00120   //! The offsets of appendages with tilt (elevation), pan (heading), and roll or nod joints (i.e. head/wrist)
00121   enum TPROffset_t {
00122     PanOffset = 0,    //!< pan/yaw/heading (horizontal)
00123     TiltOffset,     //!< tilt/pitch/elevation (vertical)
00124     //NodOffset = TiltOffset, //!< replicated tilt (could be left undefined instead...)
00125     RollOffset      //!< spin/twist final axis
00126   };
00127   
00128   //! The offsets of the individual legs, add #REKOffset_t value to access specific joint
00129   /*! @hideinitializer */
00130   enum LegOffset_t {
00131     LFrLegOffset = LegOffset+LFrLegOrder*JointsPerFrLeg, //!< beginning of left front arm's joints
00132     RFrLegOffset = LegOffset+RFrLegOrder*JointsPerFrLeg, //!< beginning of right front arm's joints
00133     LMdLegOffset = LegOffset+LMdLegOrder*JointsPerPosLeg + FrontLegExtra, //!< beginning of left middle leg's joints
00134     RMdLegOffset = LegOffset+RMdLegOrder*JointsPerPosLeg + FrontLegExtra, //!< beginning of right middle leg's joints
00135     LBkLegOffset = LegOffset+LBkLegOrder*JointsPerPosLeg + FrontLegExtra, //!< beginning of left back leg's joints
00136     RBkLegOffset = LegOffset+RBkLegOrder*JointsPerPosLeg + FrontLegExtra, //!< beginning of right back leg's joints
00137   };
00138           
00139   //! These are 'absolute' offsets for the neck joints, don't need to add to HeadOffset like TPROffset_t values do
00140   enum HeadOffset_t {
00141     HeadPanOffset = HeadOffset,      //!< pan/heading (horizontal)
00142     HeadTiltOffset, //!< tilt/elevation (vertical)
00143     HeadRollOffset,
00144   };
00145 
00146   //! The offsets of the individual LEDs
00147   /*! @hideinitializer */
00148   enum LEDOffset_t {
00149     PowerRedLEDOffset=LEDOffset,
00150     PowerGreenLEDOffset,
00151     PlayLEDOffset,
00152     AdvanceLEDOffset
00153   };
00154     
00155   const LEDOffset_t RedLEDOffset = PowerRedLEDOffset;
00156   const LEDOffset_t BlueLEDOffset = AdvanceLEDOffset; 
00157   const LEDOffset_t GreenLEDOffset = PlayLEDOffset;
00158   const LEDOffset_t YellowLEDOffset = AdvanceLEDOffset;
00159     
00160   typedef unsigned int LEDBitMask_t; //!< So you can be clear when you're refering to a LED bitmask
00161     
00162   const LEDBitMask_t BlueLEDMask = (1<<(AdvanceLEDOffset-LEDOffset)) | (1<<(PowerRedLEDOffset-LEDOffset));
00163   const LEDBitMask_t GreenLEDMask = 1<<(GreenLEDOffset-LEDOffset); //!< mask corresponding to GreenLEDOffset
00164   const LEDBitMask_t YellowLEDMask = 1<<(YellowLEDOffset-LEDOffset); //!< mask corresponding to YellowLEDOffset
00165   const LEDBitMask_t RedLEDMask = 1<<(RedLEDOffset-LEDOffset); //!< mask corresponding to RedLEDOffset
00166     
00167   const LEDBitMask_t PowerRedLEDMask = 1<<(PowerRedLEDOffset-LEDOffset); //!< mask corresponding to BlueLEDOffset
00168   const LEDBitMask_t PowerGreenLEDMask = 1<<(PowerGreenLEDOffset-LEDOffset); //!< mask corresponding to GreenLEDOffset
00169   const LEDBitMask_t PlayLEDMask = 1<<(PlayLEDOffset-LEDOffset); //!< mask corresponding to YellowLEDOffset
00170   const LEDBitMask_t AdvanceLEDMask = 1<<(AdvanceLEDOffset-LEDOffset); //!< mask corresponding to RedLEDOffset
00171     
00172   //! LEDs for the face panel (all FaceLEDPanelMask<<(0:NumFacePanelLEDs-1) entries)
00173   const LEDBitMask_t FaceLEDMask = 0;
00174   //! selects all of the leds
00175   const LEDBitMask_t AllLEDMask  = (LEDBitMask_t)~0;
00176   //@}
00177     
00178     
00179   //! Offset needed so that the centroid of the robot is correct related to the bounding box
00180   const fmat::Column<3> AgentBoundingBoxBaseFrameOffset = fmat::pack(400,70,350);
00181     
00182   //! Half of the length, width, and height of the robot.
00183   const fmat::Column<3> AgentBoundingBoxHalfDims = fmat::pack(100,100,100);
00184   //@}
00185     
00186 
00187   // *******************************
00188   //          INPUT OFFSETS
00189   // *******************************
00190 
00191 
00192   //! The order in which inputs should be stored
00193   //!@name Input Offsets
00194 
00195   //! holds offsets to different buttons in WorldState::buttons[]
00196   /*! Should be a straight mapping to the ButtonSourceIDs
00197    *
00198    *  Note that the chest (power) button is not a normal button.  It kills
00199    *  power to the motors at a hardware level, and isn't sensed in the
00200    *  normal way.  If you want to know when it is pressed (and you are
00201    *  about to shut down) see PowerSrcID::PauseSID.
00202    *
00203    *  @see WorldState::buttons @see ButtonSourceID_t
00204    * @hideinitializer */
00205   enum ButtonOffset_t { GreenButOffset, RedButOffset, YellowButOffset };
00206 
00207   //! Provides a string name for each button
00208   const char* const buttonNames[NumButtons+1] = { "GreenBut", "RedBut", "YellowBut", NULL };
00209 
00210   //! holds offset to different sensor values in WorldState::sensors[]
00211   /*! @see WorldState::sensors[] */
00212   enum SensorOffset_t {
00213     LeftIRDistOffset,
00214     CenterIRDistOffset,
00215     IRDistOffset = CenterIRDistOffset,
00216     RightIRDistOffset,
00217     LeftLuminosityOffset,
00218     CenterLuminosityOffset,
00219     RightLuminosityOffset,
00220     MicVolumeOffset,
00221     MicSpikeCountOffset,
00222     PowerRemainOffset, //! estimate of power capacity as percentage, 0-1
00223     PowerThermoOffset, //!< degrees Celcius
00224     PowerVoltageOffset, //!< volts
00225   };
00226 
00227   //! Provides a string name for each sensor
00228   const char* const sensorNames[NumSensors+1] = {
00229     "LeftIRDist", "CenterIRDist", "RightIRDist",
00230     "LeftLuminosity", "CenterLuminosity", "RightLuminosity",
00231     "MicVolume", "MicSpikeCount",
00232     "PowerRemain", "PowerThermo", "PowerVoltage", NULL
00233   };
00234   
00235   //! Names for each of the outputs
00236   const char* const outputNames[NumReferenceFrames+1] = { 
00237   // servos:
00238     "LFr:sweep","LFr:elvtr","LFr:twist1","LFr:elbow","LFr:twist2","LFr:wrist","LFr:Gripper",
00239     "RFr:sweep","RFr:elvtr","RFr:twist1","RFr:elbow","RFr:twist2","RFr:wrist","RFr:Gripper",
00240     "LMd:sweep","LMd:rotor","LMd:elvtr","LMd:knee",
00241     "RMd:sweep","RMd:rotor","RMd:elvtr","RMd:knee",
00242     "LBk:sweep","LBk:rotor","LBk:elvtr","LBk:knee",
00243     "RBk:sweep","RBk:rotor","RBk:elvtr","RBk:knee",
00244     "Thorax",
00245     "NECK:pan","NECK:tilt","NECK:roll",
00246     
00247   // LEDs
00248     "LED:LFr:sweep","LED:LFr:elvtr","LED:LFr:twist1","LED:LFr:elbow","LED:LFr:twist2","LED:LFr:wrist","LED:LFr:Gripper",
00249     "LED:RFr:sweep","LED:RFr:elvtr","LED:RFr:twist1","LED:RFr:elbow","LED:RFr:twist2","LED:RFr:wrist","LED:RFr:Gripper",
00250     "LED:LMd:sweep","LED:LMd:rotor","LED:LMd:elvtr","LED:LMd:knee",
00251     "LED:RMd:sweep","LED:RMd:rotor","LED:RMd:elvtr","LED:RMd:knee",
00252     "LED:LBk:sweep","LED:LBk:rotor","LED:LBk:elvtr","LED:LBk:knee",
00253     "LED:RBk:sweep","LED:RBk:rotor","LED:RBk:elvtr","LED:RBk:knee",
00254     "LED:Thorax",
00255     "LED:NECK:pan","LED:NECK:tilt","LED:NECK:roll",
00256         
00257   // Reference frames
00258     "BaseFrame","LFrFootFrame","RFrFootFrame","LMdFootFrame","RMdFootFrame","LBkFootFrame","RBkFootFrame",
00259         "LFrGripperFrame", "RFrGripperFrame", "CameraFrame",    //!< Gripper frame included     
00260     NULL
00261   };
00262   
00263   //! provides polymorphic robot capability detection/mapping
00264   class MantisCapabilities : public Capabilities {
00265   public:
00266     //! constructor
00267     MantisCapabilities() : Capabilities(TargetName,NumReferenceFrames,outputNames,NumButtons,buttonNames,NumSensors,sensorNames,
00268     PIDJointOffset,NumPIDJoints,LEDOffset,NumLEDs,NumOutputs) {
00269       frameToIndex["NECK:nod"] = HeadRollOffset;    
00270     }
00271   };
00272     
00273   //! allocation declared in RobotInfo.cc
00274   extern const MantisCapabilities capabilities;
00275     
00276   
00277   //! offsets into DefaultPIDs, since Dynamixel servos don't actually use PID control, but a different set of parameters
00278   enum ServoParam_t {
00279     DYNAMIXEL_SLOPE = 0,  //!< compliance slope, the proportional control (P in PID)
00280     DYNAMIXEL_PUNCH,  //!< punch, a constant added to the slope once error exceeds compliance margin
00281     DYNAMIXEL_MARGIN  //!< compliance margin, the amount of error to tolerate before triggering a torque response
00282   };
00283   
00284   //! Dynamixel servos don't use PID control.  Instead, these values indicate compliance slope (P), punch (add to P*error), compliance margin (min error to start applying torque) (see ServoParam_t)
00285   /*! I believe the torque calculation goes something like: torque = (error<compliance) ? 0 : punch + P*error
00286    *  Dynamixel servos allow different values to be supplied for CW vs. CCW motion, but we just use the same value for each */
00287   const float DefaultPIDs[NumPIDJoints][3] = {
00288     {32,32,0},{32,32,0},{32,32,0},{32,32,0},{32,32,0},{32,32,0},{32,32,0},
00289     {32,32,0},{32,32,0},{32,32,0},{32,32,0},{32,32,0},{32,32,0},{32,32,0},
00290     {32,32,0},{32,32,0},{32,32,0},{32,32,0},
00291     {32,32,0},{32,32,0},{32,32,0},{32,32,0},
00292     {32,32,0},{32,32,0},{32,32,0},{32,32,0},
00293     {32,32,0},{32,32,0},{32,32,0},{32,32,0},
00294     {32,32,0},
00295     {32,32,0},{32,32,0},{32,32,0}  
00296   };
00297   
00298   //!These values are our recommended maximum joint velocities, in rad/ms
00299   /*! a value <= 0 means infinite speed (e.g. LEDs)
00300    *  
00301    *  These limits are <b>not</b> enforced by the framework.  They are simply available for you to use as you see fit.
00302    *  HeadPointerMC and PostureMC are primary examples of included classes which do respect these values (although they can be overridden)
00303    *  
00304    *  These values were obtained from the administrators of the Sony OPEN-R BBS */
00305   const float MaxOutputSpeed[NumOutputs] = {
00306   // servos
00307     0,0,0,0,0,0,0,
00308     0,0,0,0,0,0,0,
00309     0,0,0,0,
00310     0,0,0,0,
00311     0,0,0,0,
00312     0,0,0,0,
00313     0,
00314     0,0,0,
00315   // leds
00316     0,0,0,0,0,0,0,
00317     0,0,0,0,0,0,0,
00318     0,0,0,0,
00319     0,0,0,0,
00320     0,0,0,0,
00321     0,0,0,0,
00322     0,
00323     0,0,0
00324   };
00325 
00326   #ifndef RAD
00327     //!Just a little macro for converting degrees to radians
00328   #define RAD(deg) (((deg) * (float)M_PI ) / 180.0f)
00329     //!a flag so we undef these after we're done - do you have a cleaner solution?
00330   #define __RI_RAD_FLAG
00331   #endif
00332   
00333   //! This table holds the software limits of each of the outputs, first index is the output offset, second index is MinMaxRange_t (i.e. MinRange or MaxRange)
00334   const float outputRanges[NumOutputs][2] = {
00335   // servos
00336     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00337     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00338     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00339     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00340     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00341     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, 
00342     {RAD(-100),RAD(100)},
00343     {RAD(-100),RAD(100)},{RAD(-100),RAD(100)},{RAD(-100),RAD(100)},
00344     
00345         // LED
00346     {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},
00347     {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},
00348     {0,1},{0,1},{0,1},{0,1},
00349     {0,1},{0,1},{0,1},{0,1},
00350     {0,1},{0,1},{0,1},{0,1},
00351     {0,1},{0,1},{0,1},{0,1},
00352     {0,1},
00353     {0,1},{0,1},{0,1}
00354   };
00355 
00356   //! This table holds the mechanical limits of each of the outputs, first index is the output offset, second index is MinMaxRange_t (i.e. MinRange or MaxRange)
00357   /*! Same as #outputRanges, don't know actual values because they were never specified by Sony */
00358   const float mechanicalLimits[NumOutputs][2] = {
00359   // servos
00360     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00361     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},
00362     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},{RAD(-100),RAD(100)},
00363     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},{RAD(-100),RAD(100)},
00364     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},{RAD(-100),RAD(100)},
00365     {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)}, {RAD(-100),RAD(100)},{RAD(-100),RAD(100)},
00366     {RAD(-100),RAD(100)},
00367     {RAD(-100),RAD(100)},{RAD(-100),RAD(100)},{RAD(-100),RAD(100)},
00368   // LED
00369     {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},
00370     {0,1},{0,1},{0,1},{0,1},{0,1},{0,1},{0,1},
00371     {0,1},{0,1},{0,1},{0,1},
00372     {0,1},{0,1},{0,1},{0,1},
00373     {0,1},{0,1},{0,1},{0,1},
00374     {0,1},{0,1},{0,1},{0,1},
00375     {0,1},
00376     {0,1},{0,1},{0,1}
00377   };
00378 
00379 #ifdef __RI_RAD_FLAG
00380 #undef RAD
00381 #undef __RI_RAD_FLAG
00382 #endif
00383 }
00384 
00385 /*! 
00386  * @file
00387  * @brief Defines some capabilities of the Mantis robots
00388  * @author ejt (Creator)
00389  */
00390 
00391 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:44 2016 by Doxygen 1.6.3