00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "turtlesim/turtle_frame.h"
00031
00032 #include <ros/package.h>
00033 #include <cstdlib>
00034 #include <ctime>
00035
00036 #define DEFAULT_BG_R 0x45
00037 #define DEFAULT_BG_G 0x56
00038 #define DEFAULT_BG_B 0xff
00039
00040 namespace turtlesim
00041 {
00042
00043 TurtleFrame::TurtleFrame(wxWindow* parent)
00044 : wxFrame(parent, wxID_ANY, wxT("TurtleSim"), wxDefaultPosition, wxSize(500, 500), wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER)
00045 , frame_count_(0)
00046 , id_counter_(0)
00047 {
00048 srand(time(NULL));
00049
00050 update_timer_ = new wxTimer(this);
00051 update_timer_->Start(16);
00052
00053 Connect(update_timer_->GetId(), wxEVT_TIMER, wxTimerEventHandler(TurtleFrame::onUpdate), NULL, this);
00054 Connect(wxEVT_PAINT, wxPaintEventHandler(TurtleFrame::onPaint), NULL, this);
00055
00056 nh_.setParam("background_r", DEFAULT_BG_R);
00057 nh_.setParam("background_g", DEFAULT_BG_G);
00058 nh_.setParam("background_b", DEFAULT_BG_B);
00059
00060 std::string turtles[TURTLESIM_NUM_TURTLES] =
00061 {
00062 "box-turtle.png",
00063 "robot-turtle.png",
00064 "sea-turtle.png",
00065 "diamondback.png",
00066 "electric.png"
00067 };
00068
00069 std::string images_path = ros::package::getPath("turtlesim") + "/images/";
00070 for (size_t i = 0; i < TURTLESIM_NUM_TURTLES; ++i)
00071 {
00072 turtle_images_[i].LoadFile(wxString::FromAscii((images_path + turtles[i]).c_str()));
00073 turtle_images_[i].SetMask(true);
00074 turtle_images_[i].SetMaskColour(255, 255, 255);
00075 }
00076
00077 meter_ = turtle_images_[0].GetHeight();
00078
00079 path_bitmap_ = wxBitmap(GetSize().GetWidth(), GetSize().GetHeight());
00080 path_dc_.SelectObject(path_bitmap_);
00081 clear();
00082
00083 clear_srv_ = nh_.advertiseService("clear", &TurtleFrame::clearCallback, this);
00084 reset_srv_ = nh_.advertiseService("reset", &TurtleFrame::resetCallback, this);
00085 spawn_srv_ = nh_.advertiseService("spawn", &TurtleFrame::spawnCallback, this);
00086 kill_srv_ = nh_.advertiseService("kill", &TurtleFrame::killCallback, this);
00087
00088 ROS_INFO("Starting turtlesim with node name %s", ros::this_node::getName().c_str()) ;
00089
00090 width_in_meters_ = GetSize().GetWidth() / meter_;
00091 height_in_meters_ = GetSize().GetHeight() / meter_;
00092 spawnTurtle("", width_in_meters_ / 2.0, height_in_meters_ / 2.0, 0);
00093 }
00094
00095 TurtleFrame::~TurtleFrame()
00096 {
00097 delete update_timer_;
00098 }
00099
00100 bool TurtleFrame::spawnCallback(turtlesim::Spawn::Request& req, turtlesim::Spawn::Response& res)
00101 {
00102 std::string name = spawnTurtle(req.name, req.x, req.y, req.theta);
00103 if (name.empty())
00104 {
00105 ROS_ERROR("A turtled named [%s] already exists", req.name.c_str());
00106 return false;
00107 }
00108
00109 res.name = name;
00110
00111 return true;
00112 }
00113
00114 bool TurtleFrame::killCallback(turtlesim::Kill::Request& req, turtlesim::Kill::Response&)
00115 {
00116 M_Turtle::iterator it = turtles_.find(req.name);
00117 if (it == turtles_.end())
00118 {
00119 ROS_ERROR("Tried to kill turtle [%s], which does not exist", req.name.c_str());
00120 return false;
00121 }
00122
00123 turtles_.erase(it);
00124
00125 return true;
00126 }
00127
00128 bool TurtleFrame::hasTurtle(const std::string& name)
00129 {
00130 return turtles_.find(name) != turtles_.end();
00131 }
00132
00133 std::string TurtleFrame::spawnTurtle(const std::string& name, float x, float y, float angle)
00134 {
00135 std::string real_name = name;
00136 if (real_name.empty())
00137 {
00138 do
00139 {
00140 std::stringstream ss;
00141 ss << "turtle" << ++id_counter_;
00142 real_name = ss.str();
00143 } while (hasTurtle(real_name));
00144 }
00145 else
00146 {
00147 if (hasTurtle(real_name))
00148 {
00149 return "";
00150 }
00151 }
00152
00153 TurtlePtr t(new Turtle(ros::NodeHandle(real_name), turtle_images_[rand() % TURTLESIM_NUM_TURTLES], Vector2(x, y), angle));
00154 turtles_[real_name] = t;
00155
00156 ROS_INFO("Spawning turtle [%s] at x=[%f], y=[%f], theta=[%f]", real_name.c_str(), x, y, angle);
00157
00158 return real_name;
00159 }
00160
00161 void TurtleFrame::clear()
00162 {
00163 int r = DEFAULT_BG_R;
00164 int g = DEFAULT_BG_G;
00165 int b = DEFAULT_BG_B;
00166
00167 nh_.param("background_r", r, r);
00168 nh_.param("background_g", g, g);
00169 nh_.param("background_b", b, b);
00170
00171 path_dc_.SetBackground(wxBrush(wxColour(r, g, b)));
00172 path_dc_.Clear();
00173 }
00174
00175 void TurtleFrame::onUpdate(wxTimerEvent& evt)
00176 {
00177 ros::spinOnce();
00178
00179 updateTurtles();
00180
00181 if (!ros::ok())
00182 {
00183 Close();
00184 }
00185 }
00186
00187 void TurtleFrame::onPaint(wxPaintEvent& evt)
00188 {
00189 wxPaintDC dc(this);
00190
00191 dc.DrawBitmap(path_bitmap_, 0, 0, true);
00192
00193 M_Turtle::iterator it = turtles_.begin();
00194 M_Turtle::iterator end = turtles_.end();
00195 for (; it != end; ++it)
00196 {
00197 it->second->paint(dc);
00198 }
00199 }
00200
00201 void TurtleFrame::updateTurtles()
00202 {
00203 if (last_turtle_update_.isZero())
00204 {
00205 last_turtle_update_ = ros::WallTime::now();
00206 return;
00207 }
00208
00209 if (frame_count_ % 3 == 0)
00210 {
00211 path_image_ = path_bitmap_.ConvertToImage();
00212 Refresh();
00213 }
00214
00215 M_Turtle::iterator it = turtles_.begin();
00216 M_Turtle::iterator end = turtles_.end();
00217 for (; it != end; ++it)
00218 {
00219 it->second->update(0.016, path_dc_, path_image_, path_dc_.GetBackground().GetColour(), width_in_meters_, height_in_meters_);
00220 }
00221
00222 ++frame_count_;
00223 }
00224
00225
00226 bool TurtleFrame::clearCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
00227 {
00228 ROS_INFO("Clearing turtlesim.");
00229 clear();
00230 return true;
00231 }
00232
00233 bool TurtleFrame::resetCallback(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
00234 {
00235 ROS_INFO("Resetting turtlesim.");
00236 turtles_.clear();
00237 id_counter_ = 0;
00238 spawnTurtle("", width_in_meters_ / 2.0, height_in_meters_ / 2.0, 0);
00239 clear();
00240 return true;
00241 }
00242
00243 }