5002d70320b2678538491d6984e286e93a6e9039
[bachelor-thesis/roomba_tests.git] / main.cc
1 /**
2 * @file main.cc
3 * @date 27 Nov 2010
4 * Copyright © 2010 Roland Hieber
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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
22 * THE SOFTWARE.
23 */
24
25 #include "svnrevision.h"
26 #include <iostream>
27 #include <stdint.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>
35
36 using namespace std;
37
38 #if QT_VERSION < 0x040500
39 #define getInt QInputDialog::getInteger
40 #else // QT_VERSION > 0x040500
41 #define getInt QInputDialog::getInt
42 #endif // QT_VERSION
43
44 // UART port on which we communicate with the Roomba
45 char uart[] = "/dev/ttyUSB0";
46
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;
52
53 /**
54 * Global stuff we need
55 */
56 OsModel::Os os;
57 OsModel::Timer::self_t timer;
58 Roomba roomba;
59 RoombaUart roomba_uart(os);
60 ControlledMotion ctrl_motion;
61 char * roomba_id;
62 char * ground_type;
63
64 /**
65 * Sensor data we need, filled in callback
66 */
67 struct SensorData {
68 uint16_t capacity, charge;
69 uint8_t charging;
70 int16_t current;
71 int8_t temperature;
72 uint16_t voltage;
73 int16_t left_encoder_counts, right_encoder_counts;
74 } sensor_data;
75
76 /**
77 * Callback that fills the sensor data when data is available
78 */
79 struct DataAvailable {
80 void cb(int state) {
81 if(state != Roomba::DATA_AVAILABLE) {
82 return;
83 }
84 sensor_data.capacity = roomba().capacity;
85 sensor_data.charge = roomba().charge;
86 sensor_data.charging = roomba().charging;
87 sensor_data.current = roomba().current;
88 sensor_data.voltage = roomba().voltage;
89 sensor_data.left_encoder_counts = roomba().left_encoder_counts;
90 sensor_data.right_encoder_counts = roomba().right_encoder_counts;
91 }
92 } data_available;
93
94 /**
95 * return battery status as QString
96 */
97 QString chargeText(Roomba& roomba) {
98 return QString("Battery: %1%\nPress Cancel to exit.\n\n").arg(int(float(
99 sensor_data.charge) / float(sensor_data.capacity) * 100.0));
100 }
101
102 /**
103 * drive iterations. logs values to stdout.
104 */
105 void drive(Roomba& roomba, ControlledMotion& ctrl_motion) {
106 int input_distance = 0, deviation_x = 0, deviation_y = 0, velocity = 100;
107 bool ok = false;
108
109 while(true) {
110
111 // new distance to drive
112 input_distance = getInt(0, "Input distance", chargeText(roomba)
113 + "Input new distance in mm:", input_distance,
114 numeric_limits<int>::min(), numeric_limits<int>::max(), 1, &ok);
115 if(!ok) {
116 break;
117 }
118 // new velocity
119 velocity = getInt(0, "Input velocity", chargeText(roomba)
120 + "Input drive velocity in mm/sec:", velocity, -500, 500, 10, &ok);
121 if(!ok) {
122 break;
123 }
124 ctrl_motion.move_distance(input_distance, velocity);
125 roomba.wait_for_stop();
126
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);
131 if(!ok) {
132 break;
133 }
134 deviation_y = getInt(0, "Input y deviation", chargeText(roomba)
135 + "Input travelled distance on y axis in mm:", deviation_y,
136 numeric_limits<int>::min(), numeric_limits<int>::max(), 1, &ok);
137 if(!ok) {
138 break;
139 }
140 cout << "svn=" << SVNREVISION << " roomba_id=" << roomba_id
141 << " move=straight" << " ground_type=" << ground_type
142 << " input_distance=" << input_distance << " velocity=" << velocity
143 << " internal_distance=" << roomba.distance() << " deviation_x="
144 << deviation_x << " deviation_y=" << deviation_y
145 << " encoder_ticks_left=" << sensor_data.left_encoder_counts
146 << " encoder_ticks_right=" << sensor_data.right_encoder_counts
147 << " batt_charge=" << sensor_data.charge << " batt_capacity="
148 << sensor_data.capacity << " batt_voltage=" << sensor_data.voltage
149 << " batt_current=" << sensor_data.current << endl;
150 }
151 }
152
153 /**
154 * turn iterations. logs values to stdout.
155 */
156 void turn(Roomba& roomba, ControlledMotion& ctrl_motion) {
157 int cur_angle = 0, turn_angle = 0, measured_angle = 0, velocity = 100;
158 bool ok = false;
159
160 // current angle
161 cur_angle = getInt(0, "Input current orientation", chargeText(roomba)
162 + "Input current orientation in degree:", cur_angle, 0, 359, 1, &ok);
163 if(!ok) {
164 return;
165 }
166
167 while(true) {
168 // new turn velocity
169 velocity = getInt(0, "Input velocity", chargeText(roomba)
170 + "Input turn velocity in mm/sec:", velocity, -500, 500, 10, &ok);
171 if(!ok) {
172 break;
173 }
174
175 // angle to turn about
176 turn_angle = getInt(0, "Input turn angle", chargeText(roomba)
177 + "Input angle in degree to turn about:", turn_angle,
178 numeric_limits<int>::min() + 360, numeric_limits<int>::max() - 360, 1,
179 &ok);
180 if(!ok) {
181 break;
182 }
183
184 ctrl_motion.turn_about(Math::degrees_to_radians(turn_angle), velocity);
185 roomba.wait_for_stop();
186
187 // new current angle
188 measured_angle = getInt(0, "Input measured angle", chargeText(roomba)
189 + QString("Orientation should be %1 degree now.\n\n").arg((cur_angle
190 + turn_angle) % 360) + "Input measured angle in degree the Roomba has "
191 "turned:", turn_angle, 0, numeric_limits<int>::max(), 1, &ok);
192 if(!ok) {
193 break;
194 }
195
196 cout << "svn=" << SVNREVISION << " roomba_id=" << roomba_id
197 << " move=straight" << " ground_type=" << ground_type << "turn_angle="
198 << turn_angle << " measured_angle=" << measured_angle << " velocity="
199 << velocity << " internal_angle=" << roomba.angle()
200 << " encoder_ticks_left=" << sensor_data.left_encoder_counts
201 << " encoder_ticks_right=" << sensor_data.right_encoder_counts
202 << " batt_charge=" << sensor_data.charge << " batt_capacity="
203 << sensor_data.capacity << " batt_voltage=" << sensor_data.voltage
204 << " batt_current=" << sensor_data.current << endl;
205
206 // new orientation
207 cur_angle = (cur_angle + measured_angle) % 360;
208 }
209 }
210
211 /**
212 * main function
213 */
214 int main(int argc, char ** argv) {
215
216 if(argc < 4) {
217 cerr << "Usage: " << argv[0]
218 << " --turn|-t|--drive|-d roomba-id ground-type" << endl;
219 exit(-1);
220 }
221
222 // init stuff
223 QApplication app(argc, argv);
224
225 roomba_uart.set_baudrate(19200);
226 roomba_uart.enable_serial_comm();
227 roomba.init(roomba_uart, timer, Roomba::POSITION
228 | Roomba::BATTERY_AND_TEMPERATURE);
229
230 cerr << "Got roomba at " << roomba_uart.address() << endl;
231
232 roomba.reset_distance();
233 roomba.reset_angle();
234 ctrl_motion.init(roomba);
235
236 // we do not want the probably corrupted data from roomba(), instead we fill
237 // our own values when data is available
238 roomba.register_state_callback<DataAvailable, &DataAvailable::cb> (
239 &data_available);
240
241 // fill it once
242 roomba.notify_state_receivers(Roomba::DATA_AVAILABLE);
243
244 // actual tests
245 roomba_id = argv[2];
246 ground_type = argv[3];
247 if(strcmp(argv[1], "--turn") == 0 || strcmp(argv[1], "-t") == 0) {
248 turn(roomba, ctrl_motion);
249 } else if(strcmp(argv[1], "--drive") == 0 || strcmp(argv[1], "-d") == 0) {
250 drive(roomba, ctrl_motion);
251 }
252 }
This page took 0.052694 seconds and 3 git commands to generate.