Project

General

Profile

Statistics
| Branch: | Revision:

robobuggy / buggyvis / src / buggy.cpp @ f75a88be

History | View | Annotate | Download (6.28 KB)

1
/*
2
 * Copyright (c) 2009, Willow Garage, Inc.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 *     * Redistributions of source code must retain the above copyright
9
 *       notice, this list of conditions and the following disclaimer.
10
 *     * Redistributions in binary form must reproduce the above copyright
11
 *       notice, this list of conditions and the following disclaimer in the
12
 *       documentation and/or other materials provided with the distribution.
13
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
14
 *       contributors may be used to endorse or promote products derived from
15
 *       this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
 * POSSIBILITY OF SUCH DAMAGE.
28
 */
29

    
30
#include "buggyvis/buggy.h"
31

    
32
#include <QColor>
33
#include <QRgb>
34

    
35
#define DEFAULT_PEN_R 0xb3
36
#define DEFAULT_PEN_G 0xb8
37
#define DEFAULT_PEN_B 0xff
38

    
39
namespace buggysim
40
{
41

    
42
  Turtle::Turtle(const ros::NodeHandle& nh,
43
                 const QImage& wall_image,
44
                 const QImage& turtle_image,
45
                 const QPointF& pos,
46
                 float orient)
47
    : nh_(nh)
48
    , turtle_image_(turtle_image)
49
    , wall_image_(wall_image)
50
    , pos_(pos)
51
    , orient_(orient)
52
      //, lin_vel_(2.0)
53
      //, ang_vel_(0.0)
54
      //, turnAngle_(0.0)
55
    , pen_on_(true)
56
    , pen_(QColor(DEFAULT_PEN_R, DEFAULT_PEN_G, DEFAULT_PEN_B))
57
  {
58
    pen_.setWidth(3);
59
    
60
    pose_sub_ = nh_.subscribe
61
      ("pose", 1, &Turtle::poseCallback, this);
62
    
63
    //Services
64
    set_pen_srv_ = nh_.advertiseService
65
      ("set_pen", &Turtle::setPenCallback, this);
66
    teleport_relative_srv_ = nh_.advertiseService
67
      ("teleport_relative", &Turtle::teleportRelativeCallback, this);
68
    teleport_absolute_srv_ = nh_.advertiseService
69
      ("teleport_absolute", &Turtle::teleportAbsoluteCallback, this);
70
    
71
    meter_ = turtle_image_.height();
72
    rotateImage();
73
  }
74
  
75
  void Turtle::poseCallback(const buggymsgs::PoseConstPtr& pcp)
76
  {
77
    last_command_time_ = ros::WallTime::now();
78
    pose_ = pcp->pose;
79
  }
80
  
81
  bool Turtle::setPenCallback(buggysim::SetPen::Request& req, 
82
                              buggysim::SetPen::Response&)
83
  {
84
    pen_on_ = !req.off;
85
    if (req.off)
86
      {
87
        return true;
88
      }
89

    
90
    QPen pen(QColor(req.r, req.g, req.b));
91
    if (req.width != 0)
92
      {
93
        pen.setWidth(req.width);
94
      }
95

    
96
    pen_ = pen;
97
    return true;
98
  }
99

    
100
  void Turtle::rotateImage()
101
  {
102
    QTransform transform;
103
    transform.rotate(-orient_ * 180.0 / PI + 90.0);
104
    turtle_rotated_image_ = turtle_image_.transformed(transform);
105
  }
106

    
107
  /**
108
   * TODO: convert this to take just an angle. And include drag. 
109
   *       and include acceleration/joule dump
110
   */
111
  bool Turtle::update(double dt, 
112
                      QPainter& path_painter, 
113
                      const QImage& path_image, 
114
                      qreal canvas_width, 
115
                      qreal canvas_height)
116
  {
117
    bool modified = false;
118
    qreal old_orient = orient_;
119

    
120
    // first process any teleportation requests, in order
121
    V_TeleportRequest::iterator it = teleport_requests_.begin();
122
    V_TeleportRequest::iterator end = teleport_requests_.end();
123
    for (; it != end; ++it)
124
      {
125
        const TeleportRequest& req = *it;
126

    
127
        QPointF old_pos = pos_;
128
        if (req.relative)
129
          {
130
            orient_ += req.theta;
131
            pos_.rx() += std::sin(orient_ + PI/2.0) * req.linear;
132
            pos_.ry() += std::cos(orient_ + PI/2.0) * req.linear;
133
          }
134
        else
135
          {
136
            pos_.setX(req.pos.x());
137
            pos_.setY(std::max(0.0, static_cast<double>(canvas_height - req.pos.y())));
138
            orient_ = req.theta;
139
          }
140

    
141
        path_painter.setPen(pen_);
142
        path_painter.drawLine(pos_ * meter_, old_pos * meter_);
143
        modified = true;
144
      }
145

    
146
    teleport_requests_.clear();
147

    
148
    // Stop moving after 1 second since-last command.
149

    
150
    // Update my position
151
    QPointF old_pos = pos_;
152

    
153
    // TODO: what direction does orientation start at 0?
154
    // TODO: orient might have to become negative
155
    orient_ = std::fmod(orient_ - (turnAngle_ * dt), 2*PI);
156
    if (orient_ < 0.0) {
157
      orient_ += 2*PI;
158
    }
159
    // TODO: why add pi/2? is this just because they got the 
160
    //       sin/cos mixed up?
161
    pos_.rx() += std::cos(orient_) * lin_vel_ * dt;
162
    pos_.ry() -= std::sin(orient_) * lin_vel_ * dt;
163

    
164
    // Clamp to screen size
165
    // TODO: change to use another image, to detect walls. 
166
    if (pos_.x() < 0 || pos_.x() > canvas_width ||
167
        pos_.y() < 0 || pos_.y() > canvas_height)
168
      {
169
        ROS_WARN("Oh no! I hit the wall! (Clamping from [x=%f, y=%f])", pos_.x(), pos_.y());
170
      }
171

    
172
    pos_.setX(std::min(std::max(static_cast<double>(pos_.x()), 0.0), 
173
                       static_cast<double>(canvas_width)));
174
    pos_.setY(std::min(std::max(static_cast<double>(pos_.y()), 0.0), 
175
                       static_cast<double>(canvas_height)));
176

    
177
    /** END POSITION UPDATE */
178
    buggymsgs::Pose p;
179
    p.x = pos_.x();
180
    p.y = canvas_height - pos_.y();
181
    p.angle = orient_;
182
    p.linear_velocity = lin_vel_;
183
    pose_pub_.publish(p);
184

    
185
    ROS_DEBUG("[%s]: pos_x: %f pos_y: %f theta: %f", 
186
              nh_.getNamespace().c_str(), 
187
              pos_.x(), pos_.y(), orient_);
188

    
189
    if (orient_ != old_orient)
190
      {
191
        rotateImage();
192
        modified = true;
193
      }
194

    
195
    if (pos_ != old_pos)
196
      {
197
        if (pen_on_)
198
          {
199
            path_painter.setPen(pen_);
200
            path_painter.drawLine(pos_ * meter_, old_pos * meter_);
201
          }
202
        modified = true;
203
      }
204

    
205
    return modified;
206
  }
207

    
208
  void Turtle::paint(QPainter& painter)
209
  {
210
    QPointF p = pos_ * meter_;
211
    p.rx() -= 0.5 * turtle_rotated_image_.width();
212
    p.ry() -= 0.5 * turtle_rotated_image_.height();
213
    painter.drawImage(p, turtle_rotated_image_);
214
  }
215

    
216
}