Project

General

Profile

Statistics
| Branch: | Revision:

root / scout / scoutsim / src / scout.cpp @ a8480867

History | View | Annotate | Download (8.3 KB)

1
/*
2
 * This package was developed by the CMU Robotics Club project using code
3
 * from Willow Garage, Inc.  Please see licensing.txt for details.
4
 *
5
 * All rights reserved.
6
 *
7
 * @brief Keeps track of a single scout robot.
8
 * @file scout.cpp
9
 * @author Colony Project, CMU Robotics Club
10
 * @author Alex Zirbel
11
 */
12

    
13
#include "scout.h"
14

    
15
#include <wx/wx.h>
16

    
17
#define DEFAULT_PEN_R 0xb3
18
#define DEFAULT_PEN_G 0xb8
19
#define DEFAULT_PEN_B 0xff
20

    
21
namespace scoutsim
22
{
23
    Scout::Scout(const ros::NodeHandle& nh,
24
            const wxImage& scout_image,
25
            const Vector2& pos,
26
            float orient)
27
        : n_(nh)
28
          , scout_image_(scout_image)
29
          , pos_(pos)
30
          , orient_(orient)
31
          , lin_vel_(0.0)
32
          , ang_vel_(0.0)
33
          , pen_on_(true)
34
          , pen_(wxColour(DEFAULT_PEN_R, DEFAULT_PEN_G, DEFAULT_PEN_B))
35
    {
36
        pen_.SetWidth(3);
37
        scout_ = wxBitmap(scout_image_);
38

    
39
        motors_sub_ = n_.subscribe("set_motors", 1, &Scout::setMotors, this);
40

    
41
        /// @TODO take this out!
42
        velocity_sub_ =
43
            n_.subscribe("command_velocity",
44
                          1,
45
                          &Scout::velocityCallback, this);
46
        pose_pub_ = n_.advertise<Pose>("pose", 1);
47
        color_pub_ = n_.advertise<Color>("color_sensor", 1);
48
        set_pen_srv_ = n_.advertiseService("set_pen",
49
                                            &Scout::setPenCallback,
50
                                            this);
51
        teleport_relative_srv_ =
52
            n_.advertiseService("teleport_relative",
53
                                 &Scout::teleportRelativeCallback,
54
                                 this);
55
        teleport_absolute_srv_ =
56
            n_.advertiseService("teleport_absolute",
57
                                 &Scout::teleportAbsoluteCallback,
58
                                 this);
59

    
60
        meter_ = scout_.GetHeight();
61
    }
62

    
63
    /**
64
     * A callback function that sets velocity based on a set_motors
65
     * request.
66
     */
67
    void Scout::setMotors(const motors::set_motors::ConstPtr& msg)
68
    {
69
        last_command_time_ = ros::WallTime::now();
70

    
71
        if(msg->fl_set)
72
        {
73
            motor_fl_speed_ = msg->fl_speed;
74
        }
75
        if(msg->fr_set)
76
        {
77
            motor_fr_speed_ = msg->fr_speed;
78
        }
79
        if(msg->bl_set)
80
        {
81
            motor_bl_speed_ = msg->bl_speed;
82
        }
83
        if(msg->br_set)
84
        {
85
            motor_br_speed_ = msg->br_speed;
86
        }
87

    
88
        float l_speed = (float (motor_fl_speed_ + motor_bl_speed_)) / 2;
89
        float r_speed = (float (motor_fr_speed_ + motor_br_speed_)) / 2;
90

    
91
        /// @TODO Change this!
92
        lin_vel_ = (l_speed + r_speed) / 2;
93
        ang_vel_ = r_speed - l_speed;
94

    
95
    }
96

    
97
    void Scout::velocityCallback(const VelocityConstPtr& vel)
98
    {
99
        last_command_time_ = ros::WallTime::now();
100
        lin_vel_ = vel->linear;
101
        ang_vel_ = vel->angular;
102
    }
103

    
104
    bool Scout::setPenCallback(scoutsim::SetPen::Request& req,
105
                               scoutsim::SetPen::Response&)
106
    {
107
        pen_on_ = !req.off;
108
        if (req.off)
109
        {
110
            return true;
111
        }
112

    
113
        wxPen pen(wxColour(req.r, req.g, req.b));
114
        if (req.width != 0)
115
        {
116
            pen.SetWidth(req.width);
117
        }
118

    
119
        pen_ = pen;
120
        return true;
121
    }
122

    
123
    bool Scout::teleportRelativeCallback(scoutsim::TeleportRelative::Request& req,
124
                                         scoutsim::TeleportRelative::Response&)
125
    {
126
        teleport_requests_.push_back(TeleportRequest(0,
127
                                                     0,
128
                                                     req.angular,
129
                                                     req.linear,
130
                                                     true));
131
        return true;
132
    }
133

    
134
    bool Scout::teleportAbsoluteCallback(scoutsim::TeleportAbsolute::Request& req,
135
                                         scoutsim::TeleportAbsolute::Response&)
136
    {
137
        teleport_requests_.push_back(TeleportRequest(req.x,
138
                                                     req.y,
139
                                                     req.theta,
140
                                                     0,
141
                                                     false));
142
        return true;
143
    }
144

    
145
    void Scout::update(double dt, wxMemoryDC& path_dc,
146
                        const wxImage& path_image, wxColour background_color,
147
                        float canvas_width, float canvas_height)
148
    {
149
        // first process any teleportation requests, in order
150
        V_TeleportRequest::iterator it = teleport_requests_.begin();
151
        V_TeleportRequest::iterator end = teleport_requests_.end();
152
        for (; it != end; ++it)
153
        {
154
            const TeleportRequest& req = *it;
155

    
156
            Vector2 old_pos = pos_;
157
            if (req.relative)
158
            {
159
                orient_ += req.theta;
160
                pos_.x += sin(orient_ + PI/2.0) * req.linear;
161
                pos_.y += cos(orient_ + PI/2.0) * req.linear;
162
            }
163
            else
164
            {
165
                pos_.x = req.pos.x;
166
                pos_.y = std::max(0.0f, canvas_height - req.pos.y);
167
                orient_ = req.theta;
168
            }
169

    
170
            path_dc.SetPen(pen_);
171
            path_dc.DrawLine(pos_.x * meter_, pos_.y * meter_,
172
                             old_pos.x * meter_, old_pos.y * meter_);
173
        }
174

    
175
        teleport_requests_.clear();
176

    
177
        if (ros::WallTime::now() - last_command_time_ > ros::WallDuration(1.0))
178
        {
179
            lin_vel_ = 0.0f;
180
            ang_vel_ = 0.0f;
181
        }
182

    
183
        Vector2 old_pos = pos_;
184

    
185
        orient_ = fmod(orient_ + ang_vel_ * dt, 2*PI);
186
        pos_.x += sin(orient_ + PI/2.0) * lin_vel_ * dt;
187
        pos_.y += cos(orient_ + PI/2.0) * lin_vel_ * dt;
188

    
189
        // Clamp to screen size
190
        if (pos_.x < 0 || pos_.x >= canvas_width
191
                || pos_.y < 0 || pos_.y >= canvas_height)
192
        {
193
            ROS_WARN("Oh no! I hit the wall! (Clamping from [x=%f, y=%f])", pos_.x, pos_.y);
194
        }
195

    
196
        pos_.x = std::min(std::max(pos_.x, 0.0f), canvas_width);
197
        pos_.y = std::min(std::max(pos_.y, 0.0f), canvas_height);
198

    
199
        int canvas_x = pos_.x * meter_;
200
        int canvas_y = pos_.y * meter_;
201

    
202
        {
203
            wxImage rotated_image =
204
                scout_image_.Rotate(orient_ - PI/2.0,
205
                                    wxPoint(scout_image_.GetWidth() / 2,
206
                                            scout_image_.GetHeight() / 2),
207
                                    false);
208

    
209
            for (int y = 0; y < rotated_image.GetHeight(); ++y)
210
            {
211
                for (int x = 0; x < rotated_image.GetWidth(); ++x)
212
                {
213
                    if (rotated_image.GetRed(x, y) == 255
214
                            && rotated_image.GetBlue(x, y) == 255
215
                            && rotated_image.GetGreen(x, y) == 255)
216
                    {
217
                        rotated_image.SetAlpha(x, y, 0);
218
                    }
219
                }
220
            }
221

    
222
            scout_ = wxBitmap(rotated_image);
223
        }
224

    
225
        Pose p;
226
        p.x = pos_.x;
227
        p.y = canvas_height - pos_.y;
228
        p.theta = orient_;
229
        p.linear_velocity = lin_vel_;
230
        p.angular_velocity = ang_vel_;
231
        pose_pub_.publish(p);
232

    
233
        // Figure out (and publish) the color underneath the scout
234
        {
235
            wxSize scout_size = wxSize(scout_.GetWidth(), scout_.GetHeight());
236
            Color color;
237
            color.r = path_image.GetRed(canvas_x, canvas_y);
238
            color.g = path_image.GetGreen(canvas_x, canvas_y);
239
            color.b = path_image.GetBlue(canvas_x, canvas_y);
240
            color_pub_.publish(color);
241
        }
242

    
243
        ROS_DEBUG("[%s]: pos_x: %f pos_y: %f theta: %f",
244
                  n_.getNamespace().c_str(), pos_.x, pos_.y, orient_);
245

    
246
        if (pen_on_)
247
        {
248
            if (pos_ != old_pos)
249
            {
250
                path_dc.SetPen(pen_);
251
                path_dc.DrawLine(pos_.x * meter_, pos_.y * meter_,
252
                                 old_pos.x * meter_, old_pos.y * meter_);
253
            }
254
        }
255
    }
256

    
257
    void Scout::paint(wxDC& dc)
258
    {
259
        wxSize scout_size = wxSize(scout_.GetWidth(), scout_.GetHeight());
260
        dc.DrawBitmap(scout_, pos_.x * meter_ - (scout_size.GetWidth() / 2),
261
                      pos_.y * meter_ - (scout_size.GetHeight() / 2), true);
262
    }
263

    
264
}