4 * Copyright © 2010 Roland Hieber
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "svnrevision.h"
28 #include <external_interface/pc/pc_os_model.h>
29 #include <external_interface/pc/pc_com_uart.h>
30 #include <external_interface/pc/pc_timer.h>
31 #include <intermediate/robot/roomba/roomba.h>
32 #include <intermediate/robot/controlled_motion.h>
33 #include <QApplication>
34 #include <QInputDialog>
36 #if QT_VERSION < 0x040500
37 #define getInt QInputDialog::getInteger
38 #else // QT_VERSION > 0x040500
39 #define getInt QInputDialog::getInt
44 // UART port on which we communicate with the Roomba
45 char uart
[] = "/dev/ttyUSB0";
47 typedef wiselib::PCOsModel OsModel
;
48 typedef wiselib::StandaloneMath Math
;
49 typedef wiselib::PCComUartModel
<OsModel
, uart
> RoombaUart
;
50 typedef wiselib::RoombaModel
<OsModel
, RoombaUart
> Roomba
;
51 typedef wiselib::ControlledMotion
<OsModel
, Roomba
> ControlledMotion
;
54 * Global stuff we need
57 OsModel::Timer::self_t timer
;
59 RoombaUart
roomba_uart(os
);
60 ControlledMotion ctrl_motion
;
63 * Sensor data we need, filled in callback
66 uint16_t capacity
, charge
;
71 int16_t left_encoder_counts
, right_encoder_counts
;
75 * Callback that fills the sensor data when data is available
77 struct DataAvailable
{
79 if(state
!= Roomba::DATA_AVAILABLE
) {
82 sensor_data
.capacity
= roomba().capacity
;
83 sensor_data
.charge
= roomba().charge
;
84 sensor_data
.charging
= roomba().charging
;
85 sensor_data
.current
= roomba().current
;
86 sensor_data
.voltage
= roomba().voltage
;
87 sensor_data
.left_encoder_counts
= roomba().left_encoder_counts
;
88 sensor_data
.right_encoder_counts
= roomba().right_encoder_counts
;
93 * return battery status as QString
95 QString
chargeText(Roomba
& roomba
) {
96 return QString("Battery: %1%\nPress Cancel to exit.\n\n").arg(int(float(
97 sensor_data
.charge
) / float(sensor_data
.capacity
) * 100.0));
101 * drive iterations. logs values to stdout.
103 void drive(Roomba
& roomba
, ControlledMotion
& ctrl_motion
) {
104 int input_distance
= 0, deviation_x
= 0, deviation_y
= 0, velocity
= 100;
109 // new distance to drive
110 input_distance
= getInt(0, "Input distance", chargeText(roomba
)
111 + "Input new distance in mm:", input_distance
,
112 numeric_limits
<int>::min(), numeric_limits
<int>::max(), 1, &ok
);
115 velocity
= getInt(0, "Input velocity", chargeText(roomba
)
116 + "Input drive velocity in mm/sec:", velocity
, -500, 500, 10, &ok
);
118 ctrl_motion
.move_distance(input_distance
, velocity
);
119 roomba
.wait_for_stop();
127 // measured deviation
128 deviation_x
= getInt(0, "Input x deviation", chargeText(roomba
)
129 + "Input travelled distance on x axis in mm:", deviation_x
,
130 numeric_limits
<int>::min(), numeric_limits
<int>::max(), 1, &ok
);
132 deviation_y
= getInt(0, "Input y deviation", chargeText(roomba
)
133 + "Input travelled distance on y axis in mm:", deviation_y
,
134 numeric_limits
<int>::min(), numeric_limits
<int>::max(), 1, &ok
);
136 cout
<< "svn=" << SVNREVISION
<< " input_distance=" << input_distance
137 << " velocity=" << velocity
<< " internal_distance="
138 << roomba
.distance() << " deviation_x=" << deviation_x
139 << " deviation_y=" << deviation_y
<< " encoder_ticks_left="
140 << sensor_data
.left_encoder_counts
<< " encoder_ticks_right="
141 << sensor_data
.right_encoder_counts
<< " batt_charge="
142 << sensor_data
.charge
<< " batt_capacity=" << sensor_data
.capacity
143 << " batt_voltage=" << sensor_data
.voltage
<< " batt_current="
144 << sensor_data
.current
<< endl
;
155 * turn iterations. logs values to stdout.
157 void turn(Roomba
& roomba
, ControlledMotion
& ctrl_motion
) {
158 int cur_angle
= 0, turn_angle
= 0, measured_angle
= 0, velocity
= 100;
162 cur_angle
= getInt(0, "Input current orientation", chargeText(roomba
)
163 + "Input current orientation in degree:", cur_angle
, 0, 359, 1, &ok
);
170 velocity
= getInt(0, "Input velocity", chargeText(roomba
)
171 + "Input turn velocity in mm/sec:", velocity
, -500, 500, 10, &ok
);
176 // angle to turn about
177 turn_angle
= getInt(0, "Input turn angle", chargeText(roomba
)
178 + "Input angle in degree to turn about:", turn_angle
,
179 numeric_limits
<int>::min() + 360, numeric_limits
<int>::max() - 360, 1,
185 ctrl_motion
.turn_about(Math::degrees_to_radians(turn_angle
), velocity
);
186 roomba
.wait_for_stop();
189 measured_angle
= getInt(0, "Input measured angle", chargeText(roomba
)
190 + QString("Orientation should be %1 degree now.\n\n").arg((cur_angle
191 + turn_angle
) % 360) + "Input measured angle in degree the Roomba has "
192 "turned:", turn_angle
, 0, numeric_limits
<int>::max(), 1, &ok
);
197 cout
<< "turn_angle=" << turn_angle
<< " measured_angle=" << measured_angle
198 << " velocity=" << velocity
<< " internal_angle=" << roomba
.angle()
199 << " encoder_ticks_left=" << sensor_data
.left_encoder_counts
200 << " encoder_ticks_right=" << sensor_data
.right_encoder_counts
201 << " batt_charge=" << sensor_data
.charge
<< " batt_capacity="
202 << sensor_data
.capacity
<< " batt_voltage=" << sensor_data
.voltage
203 << " batt_current=" << sensor_data
.current
<< endl
;
206 cur_angle
= (cur_angle
+ measured_angle
) % 360;
214 int main(int argc
, char ** argv
) {
217 cerr
<< "Usage: " << argv
[0] << " --turn|-t|--drive|-d" << endl
;
222 QApplication
app(argc
, argv
);
224 roomba_uart
.set_baudrate(19200);
225 roomba_uart
.enable_serial_comm();
226 roomba
.init(roomba_uart
, timer
, Roomba::POSITION
227 | Roomba::BATTERY_AND_TEMPERATURE
);
229 cerr
<< "Got roomba at " << roomba_uart
.address() << endl
;
231 roomba
.reset_distance();
232 roomba
.reset_angle();
233 ctrl_motion
.init(roomba
);
235 // we do not want the probably corrupted data from roomba(), instead we fill
236 // our own values when data is available
237 roomba
.register_state_callback
<DataAvailable
, &DataAvailable::cb
> (
241 roomba
.notify_state_receivers(Roomba::DATA_AVAILABLE
);
244 if(strcmp(argv
[1], "--turn") == 0 || strcmp(argv
[1], "-t") == 0) {
245 turn(roomba
, ctrl_motion
);
246 } else if(strcmp(argv
[1], "--drive") == 0 || strcmp(argv
[1], "-d") == 0) {
247 drive(roomba
, ctrl_motion
);