Project

General

Profile

Statistics
| Branch: | Revision:

root / scout / scoutsim / src / scout.cpp @ 144137a1

History | View | Annotate | Download (8.12 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
        : node (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 = node.subscribe("set_motors", 1, &Scout::setMotors, this);
40

    
41
        pose_pub = node.advertise<Pose>("pose", 1);
42
        color_pub = node.advertise<Color>("color_sensor", 1);
43
        set_pen_srv = node.advertiseService("set_pen",
44
                                            &Scout::setPenCallback,
45
                                            this);
46
        teleport_relative_srv =
47
            node.advertiseService("teleport_relative",
48
                                 &Scout::teleportRelativeCallback,
49
                                 this);
50
        teleport_absolute_srv =
51
            node.advertiseService("teleport_absolute",
52
                                 &Scout::teleportAbsoluteCallback,
53
                                 this);
54

    
55
        meter = scout.GetHeight();
56
    }
57

    
58
    /**
59
     * A callback function that sets velocity based on a set_motors
60
     * request.
61
     */
62
    void Scout::setMotors(const motors::set_motors::ConstPtr& msg)
63
    {
64
        last_command_time = ros::WallTime::now();
65

    
66
        if(msg->fl_set)
67
        {
68
            motor_fl_speed = msg->fl_speed;
69
        }
70
        if(msg->fr_set)
71
        {
72
            motor_fr_speed = msg->fr_speed;
73
        }
74
        if(msg->bl_set)
75
        {
76
            motor_bl_speed = msg->bl_speed;
77
        }
78
        if(msg->br_set)
79
        {
80
            motor_br_speed = msg->br_speed;
81
        }
82

    
83
        // Assume that the two motors on the same side will be set to
84
        // roughly the same speed. Does not account for slip conditions
85
        // when they are set to different speeds.
86
        float l_speed = (float (motor_fl_speed + motor_bl_speed)) / 2;
87
        float r_speed = (float (motor_fr_speed + motor_br_speed)) / 2;
88

    
89
        // Set the linear and angular speeds
90
        lin_vel = SPEED_SCALE_FACTOR * (l_speed + r_speed) / 2;
91
        ang_vel = SPEED_SCALE_FACTOR * (r_speed - l_speed);
92
    }
93

    
94
    bool Scout::setPenCallback(scoutsim::SetPen::Request& req,
95
                               scoutsim::SetPen::Response&)
96
    {
97
        pen_on = !req.off;
98
        if (req.off)
99
        {
100
            return true;
101
        }
102

    
103
        wxPen pen(wxColour(req.r, req.g, req.b));
104
        if (req.width != 0)
105
        {
106
            pen.SetWidth(req.width);
107
        }
108

    
109
        pen = pen;
110
        return true;
111
    }
112

    
113
    /// @TODO remove
114
    bool Scout::teleportRelativeCallback(scoutsim::TeleportRelative::Request& req,
115
                                         scoutsim::TeleportRelative::Response&)
116
    {
117
        teleport_requests.push_back(TeleportRequest(0,
118
                                                     0,
119
                                                     req.angular,
120
                                                     req.linear,
121
                                                     true));
122
        return true;
123
    }
124

    
125
    /// @TODO remove
126
    bool Scout::teleportAbsoluteCallback(scoutsim::TeleportAbsolute::Request& req,
127
                                         scoutsim::TeleportAbsolute::Response&)
128
    {
129
        teleport_requests.push_back(TeleportRequest(req.x,
130
                                                     req.y,
131
                                                     req.theta,
132
                                                     0,
133
                                                     false));
134
        return true;
135
    }
136

    
137
    void Scout::update(double dt, wxMemoryDC& path_dc,
138
                        const wxImage& path_image, wxColour background_color,
139
                        float canvas_width, float canvas_height)
140
    {
141
        // first process any teleportation requests, in order
142
        V_TeleportRequest::iterator it = teleport_requests.begin();
143
        V_TeleportRequest::iterator end = teleport_requests.end();
144
        for (; it != end; ++it)
145
        {
146
            const TeleportRequest& req = *it;
147

    
148
            Vector2 old_pos = pos;
149
            if (req.relative)
150
            {
151
                orient += req.theta;
152
                pos.x += sin(orient + PI/2.0) * req.linear;
153
                pos.y += cos(orient + PI/2.0) * req.linear;
154
            }
155
            else
156
            {
157
                pos.x = req.pos.x;
158
                pos.y = std::max(0.0f, canvas_height - req.pos.y);
159
                orient = req.theta;
160
            }
161

    
162
            path_dc.SetPen(pen);
163
            path_dc.DrawLine(pos.x * meter, pos.y * meter,
164
                             old_pos.x * meter, old_pos.y * meter);
165
        }
166

    
167
        teleport_requests.clear();
168

    
169
        if (ros::WallTime::now() - last_command_time > ros::WallDuration(1.0))
170
        {
171
            lin_vel = 0.0f;
172
            ang_vel = 0.0f;
173
        }
174

    
175
        Vector2 old_pos = pos;
176

    
177
        orient = fmod(orient + ang_vel * dt, 2*PI);
178
        pos.x += sin(orient + PI/2.0) * lin_vel * dt;
179
        pos.y += cos(orient + PI/2.0) * lin_vel * dt;
180

    
181
        // Clamp to screen size
182
        if (pos.x < 0 || pos.x >= canvas_width
183
                || pos.y < 0 || pos.y >= canvas_height)
184
        {
185
            ROS_WARN("Oh no! I hit the wall! (Clamping from [x=%f, y=%f])", pos.x, pos.y);
186
        }
187

    
188
        pos.x = std::min(std::max(pos.x, 0.0f), canvas_width);
189
        pos.y = std::min(std::max(pos.y, 0.0f), canvas_height);
190

    
191
        int canvas_x = pos.x * meter;
192
        int canvas_y = pos.y * meter;
193

    
194
        {
195
            wxImage rotated_image =
196
                scout_image.Rotate(orient - PI/2.0,
197
                                   wxPoint(scout_image.GetWidth() / 2,
198
                                            scout_image.GetHeight() / 2),
199
                                    false);
200

    
201
            for (int y = 0; y < rotated_image.GetHeight(); ++y)
202
            {
203
                for (int x = 0; x < rotated_image.GetWidth(); ++x)
204
                {
205
                    if (rotated_image.GetRed(x, y) == 255
206
                            && rotated_image.GetBlue(x, y) == 255
207
                            && rotated_image.GetGreen(x, y) == 255)
208
                    {
209
                        rotated_image.SetAlpha(x, y, 0);
210
                    }
211
                }
212
            }
213

    
214
            scout = wxBitmap(rotated_image);
215
        }
216

    
217
        Pose p;
218
        p.x = pos.x;
219
        p.y = canvas_height - pos.y;
220
        p.theta = orient;
221
        p.linear_velocity = lin_vel;
222
        p.angular_velocity = ang_vel;
223
        pose_pub.publish(p);
224

    
225
        // Figure out (and publish) the color underneath the scout
226
        {
227
            wxSize scout_size = wxSize(scout.GetWidth(), scout.GetHeight());
228
            Color color;
229
            color.r = path_image.GetRed(canvas_x, canvas_y);
230
            color.g = path_image.GetGreen(canvas_x, canvas_y);
231
            color.b = path_image.GetBlue(canvas_x, canvas_y);
232
            color_pub.publish(color);
233
        }
234

    
235
        ROS_DEBUG("[%s]: pos_x: %f pos_y: %f theta: %f",
236
                  node.getNamespace().c_str(), pos.x, pos.y, orient);
237

    
238
        if (pen_on)
239
        {
240
            if (pos != old_pos)
241
            {
242
                path_dc.SetPen(pen);
243
                path_dc.DrawLine(pos.x * meter, pos.y * meter,
244
                                 old_pos.x * meter, old_pos.y * meter);
245
            }
246
        }
247
    }
248

    
249
    void Scout::paint(wxDC& dc)
250
    {
251
        wxSize scout_size = wxSize(scout.GetWidth(), scout.GetHeight());
252
        dc.DrawBitmap(scout, pos.x * meter - (scout_size.GetWidth() / 2),
253
                      pos.y * meter - (scout_size.GetHeight() / 2), true);
254
    }
255

    
256
}