00001
00002
00003
00004
00005
00006
00007
00008
00017 #include <angles/angles.h>
00018
00019 #include <art/conversions.h>
00020 #include <art/frames.h>
00021 #include <art/UTM.h>
00022
00023 #include <art_msgs/BrakeState.h>
00024 #include <art_msgs/Shifter.h>
00025 #include <art_msgs/SteeringState.h>
00026 #include <art_msgs/ThrottleState.h>
00027 #include <art/steering.h>
00028
00029 #include <art_msgs/GpsInfo.h>
00030
00031 #include "vehicle_model.h"
00032
00033 void ArtVehicleModel::setup(void)
00034 {
00035 int qDepth = 1;
00036 ros::TransportHints noDelay = ros::TransportHints().tcpNoDelay(true);
00037
00038 odom_pub_ =
00039 node_.advertise<nav_msgs::Odometry>(ns_prefix_ + "odom", qDepth);
00040 ground_truth_pub_ =
00041 node_.advertise<nav_msgs::Odometry>(ns_prefix_ + "ground_truth", qDepth);
00042 imu_pub_ =
00043 node_.advertise<sensor_msgs::Imu>(ns_prefix_ + "imu", qDepth);
00044 gps_pub_ =
00045 node_.advertise<art_msgs::GpsInfo>(ns_prefix_ + "gps", qDepth);
00046
00047
00048 brake_sub_ =
00049 node_.subscribe(ns_prefix_ + "brake/state", qDepth,
00050 &ArtVehicleModel::brakeReceived, this, noDelay);
00051 shifter_sub_ =
00052 node_.subscribe(ns_prefix_ + "shifter/state", qDepth,
00053 &ArtVehicleModel::shifterReceived, this, noDelay);
00054 steering_sub_ =
00055 node_.subscribe(ns_prefix_ + "steering/state", qDepth,
00056 &ArtVehicleModel::steeringReceived, this, noDelay);
00057 throttle_sub_ =
00058 node_.subscribe(ns_prefix_ + "throttle/state", qDepth,
00059 &ArtVehicleModel::throttleReceived, this, noDelay);
00060
00061
00062 ros::NodeHandle private_nh("~");
00063 private_nh.param("latitude", origin_lat_, 29.446018);
00064 private_nh.param("longitude", origin_long_, -98.607024);
00065 private_nh.param("elevation", origin_elev_, 100.0);
00066 ROS_INFO("map GPS origin: latitude %.6f, longitude %.6f, elevation %.1f m",
00067 origin_lat_, origin_long_, origin_elev_);
00068
00069
00070 UTM::LLtoUTM(origin_lat_, origin_long_,
00071 origin_northing_, origin_easting_, origin_zone_);
00072 ROS_INFO("Map origin UTM: %s, %.2f, %.2f",
00073 origin_zone_, origin_easting_, origin_northing_);
00074
00075
00076 double grid_x = (rint(origin_easting_/UTM::grid_size) * UTM::grid_size);
00077 double grid_y = (rint(origin_northing_/UTM::grid_size) * UTM::grid_size);
00078 ROS_INFO("UTM grid origin: (%.f, %.f)", grid_x , grid_y);
00079
00080
00081 map_origin_x_ = origin_easting_ - grid_x;
00082 map_origin_y_ = origin_northing_ - grid_y;
00083 ROS_INFO("MapXY origin: (%.f, %.f)", map_origin_x_ , map_origin_y_);
00084 }
00085
00086
00087
00088
00089
00090
00091 void
00092 ArtVehicleModel::brakeReceived(const art_msgs::BrakeState::ConstPtr &msg)
00093 {
00094
00095 boost::mutex::scoped_lock lock(msg_lock_);
00096 brake_position_ = msg->position;
00097 }
00098
00099 void
00100 ArtVehicleModel::shifterReceived(const art_msgs::Shifter::ConstPtr &msg)
00101 {
00102 ROS_DEBUG("shifter state received: gear %u", msg->gear);
00103 boost::mutex::scoped_lock lock(msg_lock_);
00104 shifter_gear_ = msg->gear;
00105 }
00106
00107 void
00108 ArtVehicleModel::steeringReceived(const art_msgs::SteeringState::ConstPtr &msg)
00109 {
00110
00111 boost::mutex::scoped_lock lock(msg_lock_);
00112 steering_angle_ = msg->angle;
00113 }
00114
00115 void
00116 ArtVehicleModel::throttleReceived(const art_msgs::ThrottleState::ConstPtr &msg)
00117 {
00118
00119 boost::mutex::scoped_lock lock(msg_lock_);
00120 throttle_position_ = msg->position;
00121 }
00122
00137 void ArtVehicleModel::ModelAcceleration(geometry_msgs::Twist *odomVel,
00138 sensor_msgs::Imu *imuMsg,
00139 ros::Time sim_time)
00140 {
00141
00142 boost::mutex::scoped_lock lock(msg_lock_);
00143
00144 double speed = fabs(odomVel->linear.x);
00145
00146
00147
00148 static const double g = 9.81;
00149 static const double throttle_accel = g;
00150 static const double brake_decel = g;
00151 static const double rolling_resistance = 0.01 * g;
00152 static const double drag_coeff = 0.01;
00153
00154
00155 static const double idle_accel = (rolling_resistance
00156 + drag_coeff * 3.1 * 3.1);
00157
00158 double wind_resistance = drag_coeff * speed * speed;
00159 double accel = (idle_accel
00160 + throttle_position_ * throttle_accel
00161 - brake_position_ * brake_decel
00162 - rolling_resistance
00163 - wind_resistance);
00164
00165
00166 double deltaT = ros::Duration(sim_time - last_update_time_).toSec();
00167 speed += accel * deltaT;
00168 imuMsg->linear_acceleration.x = accel;
00169
00170
00171
00172 if (speed < 0.0)
00173 {
00174 speed = 0.0;
00175 imuMsg->linear_acceleration.x = 0.0;
00176 }
00177
00178
00179 odomVel->linear.x = speed;
00180 if (shifter_gear_ == art_msgs::Shifter::Reverse)
00181 odomVel->linear.x = -speed;
00182
00183
00184 odomVel->angular.z = Steering::angle_to_yaw(odomVel->linear.x,
00185 steering_angle_);
00186 imuMsg->angular_velocity.z = odomVel->angular.z;
00187
00188
00189
00190 double angleRadians = angles::from_degrees(steering_angle_);
00191 ROS_DEBUG("Stage SetSpeed(%.3f, %.3f, %.3f)",
00192 odomVel->linear.x, odomVel->linear.y, angleRadians);
00193 stgp_->SetSpeed(odomVel->linear.x, odomVel->linear.y, angleRadians);
00194 }
00195
00196
00197 void ArtVehicleModel::update(ros::Time sim_time)
00198 {
00199 sensor_msgs::Imu imu_msg;
00200
00201
00202 ModelAcceleration(&odomMsg_.twist.twist, &imu_msg, sim_time);
00203
00204
00205
00206 odomMsg_.pose.pose.position.x = stgp_->est_pose.x + map_origin_x_;
00207 odomMsg_.pose.pose.position.y = stgp_->est_pose.y + map_origin_y_;
00208 odomMsg_.pose.pose.position.z = origin_elev_;
00209 odomMsg_.pose.pose.orientation =
00210 tf::createQuaternionMsgFromYaw(stgp_->est_pose.a);
00211
00212 odomMsg_.header.stamp = sim_time;
00213 odomMsg_.header.frame_id = tf_prefix_ + ArtFrames::earth;
00214 odomMsg_.child_frame_id = tf_prefix_ + ArtFrames::vehicle;
00215 odom_pub_.publish(odomMsg_);
00216
00217
00218 imu_msg.header.stamp = sim_time;
00219 imu_msg.header.frame_id = tf_prefix_ + ArtFrames::vehicle;
00220 imu_msg.orientation = odomMsg_.pose.pose.orientation;
00221 imu_pub_.publish(imu_msg);
00222
00223
00224 tf::Quaternion vehicleQ;
00225 tf::quaternionMsgToTF(odomMsg_.pose.pose.orientation, vehicleQ);
00226 tf::Transform txEarth(vehicleQ,
00227 tf::Point(odomMsg_.pose.pose.position.x,
00228 odomMsg_.pose.pose.position.y,
00229 odomMsg_.pose.pose.position.z));
00230 tf_->sendTransform(tf::StampedTransform(txEarth, sim_time,
00231 tf_prefix_ + ArtFrames::earth,
00232 tf_prefix_ + ArtFrames::vehicle));
00233
00234
00235
00236 tf::Transform txOdom(tf::Quaternion(0.0, 0.0, 0.0, 1.0),
00237 tf::Point(0.0, 0.0, -odomMsg_.pose.pose.position.z));
00238 tf_->sendTransform(tf::StampedTransform(txOdom, sim_time,
00239 tf_prefix_ + ArtFrames::odom,
00240 tf_prefix_ + ArtFrames::earth));
00241
00242
00243
00244 Stg::Pose gpose = stgp_->GetGlobalPose();
00245 Stg::Velocity gvel = stgp_->GetGlobalVelocity();
00246 tf::Quaternion gposeQ;
00247 gposeQ.setRPY(0.0, 0.0, gpose.a-M_PI/2.0);
00248 tf::Transform gt(gposeQ, tf::Point(gpose.y, -gpose.x, 0.0));
00249 tf::Quaternion gvelQ;
00250 gvelQ.setRPY(0.0, 0.0, gvel.a-M_PI/2.0);
00251 tf::Transform gv(gvelQ, tf::Point(gvel.y, -gvel.x, 0.0));
00252
00253 groundTruthMsg_.pose.pose.position.x = gt.getOrigin().x();
00254 groundTruthMsg_.pose.pose.position.y = gt.getOrigin().y();
00255 groundTruthMsg_.pose.pose.position.z = gt.getOrigin().z();
00256 groundTruthMsg_.pose.pose.orientation.x = gt.getRotation().x();
00257 groundTruthMsg_.pose.pose.orientation.y = gt.getRotation().y();
00258 groundTruthMsg_.pose.pose.orientation.z = gt.getRotation().z();
00259 groundTruthMsg_.pose.pose.orientation.w = gt.getRotation().w();
00260 groundTruthMsg_.twist.twist.linear.x = gv.getOrigin().x();
00261 groundTruthMsg_.twist.twist.linear.y = gv.getOrigin().y();
00262 groundTruthMsg_.twist.twist.angular.z = gvel.a;
00263 groundTruthMsg_.header.stamp = sim_time;
00264 groundTruthMsg_.header.frame_id = tf_prefix_ + ArtFrames::odom;
00265 groundTruthMsg_.child_frame_id = tf_prefix_ + ArtFrames::vehicle;
00266 ground_truth_pub_.publish(groundTruthMsg_);
00267
00268 publishGPS(sim_time);
00269
00270 last_update_time_ = sim_time;
00271 }
00272
00273 void ArtVehicleModel::publishGPS(ros::Time sim_time)
00274 {
00275 art_msgs::GpsInfo gpsi;
00276
00277 gpsi.header.stamp = sim_time;
00278 gpsi.header.frame_id = tf_prefix_ + ArtFrames::odom;
00279
00280
00281 gpsi.utm_e = (odomMsg_.pose.pose.position.x
00282 - map_origin_x_ + origin_easting_);
00283 gpsi.utm_n = (odomMsg_.pose.pose.position.y
00284 - map_origin_y_ + origin_northing_);
00285
00286 UTM::UTMtoLL(gpsi.utm_n, gpsi.utm_e, origin_zone_,
00287 gpsi.latitude, gpsi.longitude);
00288
00289 gpsi.zone = origin_zone_;
00290 gpsi.altitude = odomMsg_.pose.pose.position.z;
00291 gpsi.quality = art_msgs::GpsInfo::DGPS_FIX;
00292 gpsi.num_sats = 9;
00293
00294 gps_pub_.publish(gpsi);
00295 }