PPSClient.cpp 21.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//    ROS node that manages the student's setup.
//    Copyright (C) 2017  Cyrill Burgener, Marco Mueller, Philipp Friedli
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "ros/ros.h"
muelmarc's avatar
muelmarc committed
18
#include <stdlib.h>
19
#include <std_msgs/String.h>
20
#include <rosbag/bag.h>
muelmarc's avatar
muelmarc committed
21
#include <ros/package.h>
22

23
#include "d_fall_pps/Controller.h"
24
#include "d_fall_pps/CMQuery.h"
25
26

#include "d_fall_pps/ViconData.h"
27
#include "d_fall_pps/CrazyflieData.h"
28
#include "d_fall_pps/ControlCommand.h"
muelmarc's avatar
muelmarc committed
29
#include "d_fall_pps/CrazyflieContext.h"
30
#include "d_fall_pps/Setpoint.h"
31
#include "std_msgs/Int32.h"
32

muelmarc's avatar
muelmarc committed
33

34
#include "d_fall_pps/ControlCommand.h"
35

36
#define CMD_USE_SAFE_CONTROLLER   1
37
#define CMD_USE_CUSTOM_CONTROLLER 2
38
39
40
41
42
43
44
45
46
47
#define CMD_CRAZYFLY_TAKE_OFF     3
#define CMD_CRAZYFLY_LAND         4
#define CMD_CRAZYFLY_MOTORS_OFF   5

// Flying states
#define STATE_MOTORS_OFF 1
#define STATE_TAKE_OFF   2
#define STATE_FLYING     3
#define STATE_LAND       4

48
49
50
51
52
53
54
55
56
57
58
// commands for CrazyRadio
#define CMD_RECONNECT  0
#define CMD_DISCONNECT 1


// CrazyRadio states:
#define CONNECTED        0
#define CONNECTING       1
#define DISCONNECTED     2

// parameters for take off and landing. Eventually will go in YAML file
59
60
#define TAKE_OFF_OFFSET  1    //in meters
#define LANDING_DISTANCE 0.15    //in meters
roangel's avatar
roangel committed
61
62
#define DURATION_TAKE_OFF  3   // seconds
#define DURATION_LANDING   3   // seconds
63

64
65
#define PI 3.141592653589

66
using namespace d_fall_pps;
67

68
69
//studentID, gives namespace and identifier in CentralManagerService
int studentID;
70

71
//the safe controller specified in the ClientConfig.yaml, is considered stable
72
ros::ServiceClient safeController;
73
//the custom controller specified in the ClientConfig.yaml, is considered potentially unstable
74
ros::ServiceClient customController;
75

76
77
78
//values for safteyCheck
bool strictSafety;
float angleMargin;
79

80
81
Setpoint controller_setpoint;

82
ros::ServiceClient centralManager;
83
ros::Publisher controlCommandPublisher;
84

85
86
87
// communicate with safeControllerService, setpoint, etc...
ros::Publisher safeControllerServiceSetpointPublisher;

88
89
90
// publisher for flying state
ros::Publisher flyingStatePublisher;

91
92
93
94
95
96
// publisher to send commands to itself.
ros::Publisher commandPublisher;

// communication with crazyRadio node. Connect and disconnect
ros::Publisher crazyRadioCommandPublisher;

97
98
rosbag::Bag bag;

99
100
101
102
// variables for the states:
int flying_state;
bool changed_state_flag;

103
104
105
// variable for crazyradio status
int crazyradio_status;

106
107
//describes the area of the crazyflie and other parameters
CrazyflieContext context;
108

109
110
//wheter to use safe of custom controller
bool usingSafeController;
111

112
113
std::string ros_namespace;

114
115
116
117
118
float take_off_distance;
float landing_distance;
float duration_take_off;
float duration_landing;

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

void loadSafeController() {
	ros::NodeHandle nodeHandle("~");

	std::string safeControllerName;
	if(!nodeHandle.getParam("safeController", safeControllerName)) {
		ROS_ERROR("Failed to get safe controller name");
		return;
	}

	ros::service::waitForService(safeControllerName);
	safeController = ros::service::createClient<Controller>(safeControllerName, true);
    ROS_INFO_STREAM("loaded safe controller: " << safeController.getService());
}

134
135
void loadCustomController()
{
136
137
138
	ros::NodeHandle nodeHandle("~");

	std::string customControllerName;
139
140
	if(!nodeHandle.getParam("customController", customControllerName))
    {
141
142
143
144
		ROS_ERROR("Failed to get custom controller name");
		return;
	}

145
    customController = ros::service::createClient<Controller>(customControllerName, true);
146
147
148
    ROS_INFO_STREAM("loaded custom controller " << customControllerName);
}

149

150
//checks if crazyflie is within allowed area and if custom controller returns no data
151
bool safetyCheck(CrazyflieData data, ControlCommand controlCommand) {
152
	//position check
153
	if((data.x < context.localArea.xmin) or (data.x > context.localArea.xmax)) {
154
		ROS_INFO_STREAM("x safety failed");
155
		return false;
muelmarc's avatar
muelmarc committed
156
	}
157
	if((data.y < context.localArea.ymin) or (data.y > context.localArea.ymax)) {
158
		ROS_INFO_STREAM("y safety failed");
159
		return false;
muelmarc's avatar
muelmarc committed
160
	}
161
	if((data.z < context.localArea.zmin) or (data.z > context.localArea.zmax)) {
162
		ROS_INFO_STREAM("z safety failed");
163
		return false;
muelmarc's avatar
muelmarc committed
164
	}
165

166
167
168
169
170
171
172
173
174
175
176
177
178
	//attitude check
	//if strictSafety is set to true in ClientConfig.yaml the SafeController takes also over if the roll and pitch angles get to large
	//the angleMargin is a value in the range (0,1). The closer to 1, the closer to 90 deg are the roll and pitch angles allowed to become before the safeController takes over
	if(strictSafety){
		if((data.roll > PI/2*angleMargin) or (data.roll < -PI/2*angleMargin)) {
			ROS_INFO_STREAM("roll too big.");
			return false;
		}
		if((data.pitch > PI/2*angleMargin) or (data.pitch < -PI/2*angleMargin)) {
			ROS_INFO_STREAM("pitch too big.");
			return false;
		}
	}
179

180
	return true;
181
}
phfriedl's avatar
phfriedl committed
182

bucyril's avatar
bucyril committed
183
184
185
186
void coordinatesToLocal(CrazyflieData& cf) {
	AreaBounds area = context.localArea;
	float originX = (area.xmin + area.xmax) / 2.0;
	float originY = (area.ymin + area.ymax) / 2.0;
187
188
189
    // change Z origin to zero, i.e., to the table height, zero of global coordinates, instead of middle of the box
    float originZ = 0.0;
	// float originZ = (area.zmin + area.zmax) / 2.0;
bucyril's avatar
bucyril committed
190
191
192
193
194
195

	cf.x -= originX;
	cf.y -= originY;
	cf.z -= originZ;
}

196
197
198
199
200
201
202
203


void takeOffCF(CrazyflieData& current_local_coordinates) //local because the setpoint is in local coordinates
{
    // set the setpoint and call safe controller
    Setpoint setpoint_msg;
    setpoint_msg.x = current_local_coordinates.x;           // previous one
    setpoint_msg.y = current_local_coordinates.y;           //previous one
204
    setpoint_msg.z = current_local_coordinates.z + take_off_distance;           //previous one plus some offset
205
206
    // setpoint_msg.yaw = current_local_coordinates.yaw;          //previous one
    setpoint_msg.yaw = 0.0;
207
    safeControllerServiceSetpointPublisher.publish(setpoint_msg);
208
209
210
211
212
    ROS_INFO("Take OFF:");
    ROS_INFO("------Current coordinates:");
    ROS_INFO("X: %f, Y: %f, Z: %f", current_local_coordinates.x, current_local_coordinates.y, current_local_coordinates.z);
    ROS_INFO("------New coordinates:");
    ROS_INFO("X: %f, Y: %f, Z: %f", setpoint_msg.x, setpoint_msg.y, setpoint_msg.z);
213
214
215
216
217
218
219
220
221
222
223
224
225

    // now, use safe controller to go to that setpoint
    usingSafeController = true;
    loadSafeController();
    // when do we finish? after some time with delay?
}

void landCF(CrazyflieData& current_local_coordinates)
{
    // set the setpoint and call safe controller
    Setpoint setpoint_msg;
    setpoint_msg.x = current_local_coordinates.x;           // previous one
    setpoint_msg.y = current_local_coordinates.y;           //previous one
226
    setpoint_msg.z = landing_distance;           //previous one plus some offset
227
228
229
230
231
232
233
234
235
236
    setpoint_msg.yaw = current_local_coordinates.yaw;          //previous one
    safeControllerServiceSetpointPublisher.publish(setpoint_msg);

    // now, use safe controller to go to that setpoint
    usingSafeController = true;
    loadSafeController();
}

void changeFlyingStateTo(int new_state)
{
237
238
239
240
241
242
243
244
245
246
247
    if(crazyradio_status == CONNECTED)
    {
        ROS_INFO("Change state to: %d", new_state);
        flying_state = new_state;
    }
    else
    {
        ROS_INFO("Disconnected and trying to change state. Stays goes to MOTORS OFF");
        flying_state = STATE_MOTORS_OFF;
    }

248
    changed_state_flag = true;
249
250
251
    std_msgs::Int32 flying_state_msg;
    flying_state_msg.data = flying_state;
    flyingStatePublisher.publish(flying_state_msg);
252
253
254
255
256
}

bool finished_take_off = false;
bool finished_land = false;

roangel's avatar
roangel committed
257
258
259
260
261
262
263
264
265
266
267
268
269
ros::Timer timer_takeoff;
ros::Timer timer_land;

void takeOffTimerCallback(const ros::TimerEvent&)
{
    finished_take_off = true;
}

void landTimerCallback(const ros::TimerEvent&)
{
    finished_land = true;
}

270
void goToControllerSetpoint()
271
{
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
    // std::vector<float> default_setpoint(4);
    // ros::NodeHandle nh_safeControllerService(ros_namespace + "/SafeControllerService");

    // ROS_INFO_STREAM(ros_namespace << "/SafeControllerService");

    // if(!nh_safeControllerService.getParam("defaultSetpoint", default_setpoint))
    // {
    //     ROS_ERROR_STREAM("couldn't find parameter 'defaultSetpoint'");
    // }

    // Setpoint setpoint_msg;
    // setpoint_msg.y = default_setpoint[1];
    // setpoint_msg.z = default_setpoint[2];
    // ROS_INFO_STREAM("Z =" << default_setpoint[2]);
    // setpoint_msg.yaw = default_setpoint[3];
    safeControllerServiceSetpointPublisher.publish(controller_setpoint);
288
289
}

290
//is called when new data from Vicon arrives
bucyril's avatar
bucyril committed
291
void viconCallback(const ViconData& viconData) {
292
	for(std::vector<CrazyflieData>::const_iterator it = viconData.crazyflies.begin(); it != viconData.crazyflies.end(); ++it) {
bucyril's avatar
bucyril committed
293
		CrazyflieData global = *it;
294

295
        if(global.crazyflieName == context.crazyflieName)
296
        {
297
298
299
300
301
            Controller controllerCall;
            CrazyflieData local = global;
            coordinatesToLocal(local);
            controllerCall.request.ownCrazyflie = local;

roangel's avatar
roangel committed
302
303
            ros::NodeHandle nodeHandle("~");

304
305
306
307
308
309
            switch(flying_state) //things here repeat every X ms, non-blocking stuff
            {
                case STATE_MOTORS_OFF: // here we will put the code of current disabled button
                    if(changed_state_flag) // stuff that will be run only once when changing state
                    {
                        changed_state_flag = false;
310
                        ROS_INFO("STATE_MOTORS_OFF");
311
312
313
314
315
316
317
318
                    }
                    break;
                case STATE_TAKE_OFF: //we need to move up from where we are now.
                    if(changed_state_flag) // stuff that will be run only once when changing state
                    {
                        changed_state_flag = false;
                        takeOffCF(local);
                        finished_take_off = false;
319
                        ROS_INFO("STATE_TAKE_OFF");
320
                        timer_takeoff = nodeHandle.createTimer(ros::Duration(duration_take_off), takeOffTimerCallback, true);
321
322
323
324
325
326
327
328
329
330
331
                    }
                    if(finished_take_off)
                    {
                        finished_take_off = false;
                        changeFlyingStateTo(STATE_FLYING);
                    }
                    break;
                case STATE_FLYING:
                    if(changed_state_flag) // stuff that will be run only once when changing state
                    {
                        changed_state_flag = false;
332
333
                        // need to change setpoint to the controller one
                        goToControllerSetpoint();
334
                        ROS_INFO("STATE_FLYING");
335
336
337
338
339
340
341
342
                    }
                    break;
                case STATE_LAND:
                    if(changed_state_flag) // stuff that will be run only once when changing state
                    {
                        changed_state_flag = false;
                        landCF(local);
                        finished_land = false;
343
                        ROS_INFO("STATE_LAND");
344
                        timer_takeoff = nodeHandle.createTimer(ros::Duration(duration_landing), landTimerCallback, true);
345
346
347
348
349
350
351
352
353
354
                    }
                    if(finished_land)
                    {
                        finished_land = false;
                        changeFlyingStateTo(STATE_MOTORS_OFF);
                    }
                    break;
                default:
                    break;
            }
355

356
357
358
359
360
361
362
            // control part that should always be running, calls to controller, computation of control output
            if(flying_state != STATE_MOTORS_OFF)
            {
                if(!global.occluded)    //if it is not occluded, then proceed to compute the controller output.
                {
                    if(!usingSafeController && flying_state == STATE_FLYING) // only enter in custom controller if we are not using safe controller AND the flying state is FLYING
                    {
363
                        bool success = customController.call(controllerCall);
364
365
                        if(!success)
                        {
366
367
368
369
                            ROS_ERROR("Failed to call custom controller, switching to safe controller");
                            ROS_ERROR_STREAM("custom controller status: valid: " << customController.isValid() << ", exists: " << customController.exists());
                            ROS_ERROR_STREAM("custom controller name: " << customController.getService());
                            usingSafeController = true;
370
371
372
                        }
                        else if(!safetyCheck(global, controllerCall.response.controlOutput))
                        {
373
374
375
376
                            usingSafeController = true;
                            ROS_INFO_STREAM("safety check failed, switching to safe controller");
                        }
                    }
377
378
                    else
                    {
379
380
381
382
383
384
385
386
387
388
389
390
391
392
                        bool success = safeController.call(controllerCall);
                        if(!success) {
                            ROS_ERROR_STREAM("Failed to call safe controller, valid: " << safeController.isValid() << ", exists: " << safeController.exists());
                        }
                    }

                    //ROS_INFO_STREAM("safe controller active: " << usingSafeController);

                    controlCommandPublisher.publish(controllerCall.response.controlOutput);

                    bag.write("ViconData", ros::Time::now(), local);
                    bag.write("ControlOutput", ros::Time::now(), controllerCall.response.controlOutput);
                }
            }
393
394
395
396
397
398
399
400
            else
            {
                ControlCommand zeroOutput = ControlCommand(); //everything set to zero
                zeroOutput.onboardControllerType = 2; //set to motor_mode
                controlCommandPublisher.publish(zeroOutput);
                bag.write("ViconData", ros::Time::now(), local);
                bag.write("ControlOutput", ros::Time::now(), zeroOutput);
            }
401
        }
402
403
404
405
	}
}

void loadParameters(ros::NodeHandle& nodeHandle) {
406
407
408
	if(!nodeHandle.getParam("studentID", studentID)) {
		ROS_ERROR("Failed to get studentID");
	}
409
410
411
412
413
414
415
416
	if(!nodeHandle.getParam("strictSafety", strictSafety)) {
		ROS_ERROR("Failed to get strictSafety param");
		return;
	}
	if(!nodeHandle.getParam("angleMargin", angleMargin)) {
		ROS_ERROR("Failed to get angleMargin param");
		return;
	}
417
418
419
420
421
422
423
424
425
}

void loadSafeControllerParameters()
{
    ros::NodeHandle nh_safeControllerService(ros_namespace + "/SafeControllerService");
    if(!nh_safeControllerService.getParam("takeOffDistance", take_off_distance))
    {
		ROS_ERROR("Failed to get takeOffDistance");
	}
426

427
428
429
430
    if(!nh_safeControllerService.getParam("landingDistance", landing_distance))
    {
		ROS_ERROR("Failed to get landing_distance");
	}
431

432
433
434
435
436
437
438
439
440
    if(!nh_safeControllerService.getParam("durationTakeOff", duration_take_off))
    {
		ROS_ERROR("Failed to get duration_take_off");
	}

    if(!nh_safeControllerService.getParam("durationLanding", duration_landing))
    {
		ROS_ERROR("Failed to get duration_landing");
	}
441
442
}

443
void loadCrazyflieContext() {
444
445
	CMQuery contextCall;
	contextCall.request.studentID = studentID;
Cyrill Burgener's avatar
Cyrill Burgener committed
446
	ROS_INFO_STREAM("StudentID:" << studentID);
447

448
449
    CrazyflieContext new_context;

450
451
452
	centralManager.waitForExistence(ros::Duration(-1));

	if(centralManager.call(contextCall)) {
453
454
		new_context = contextCall.response.crazyflieContext;
		ROS_INFO_STREAM("CrazyflieContext:\n" << new_context);
455
	} else {
456
		ROS_ERROR("Failed to load context");
457
	}
458

459
460
    if((context.crazyflieName != "") && (new_context.crazyflieName != context.crazyflieName)) //linked crazyflie name changed and it was not empty before
    {
461
462
463

        // Motors off is done in python script now everytime we disconnect

464
        // send motors OFF and disconnect before setting context = new_context
465
466
467
        // std_msgs::Int32 msg;
        // msg.data = CMD_CRAZYFLY_MOTORS_OFF;
        // commandPublisher.publish(msg);
468

469
        ROS_INFO("CF is now different for this student. Disconnect and turn it off");
470

471
        std_msgs::Int32 msg;
472
473
474
475
476
477
        msg.data = CMD_DISCONNECT;
        crazyRadioCommandPublisher.publish(msg);
    }

    context = new_context;

478
479
	ros::NodeHandle nh("CrazyRadio");
	nh.setParam("crazyFlieAddress", context.crazyflieAddress);
480
}
481

482

483
484
485

void commandCallback(const std_msgs::Int32& commandMsg) {
	int cmd = commandMsg.data;
486

487
488
	switch(cmd) {
    	case CMD_USE_SAFE_CONTROLLER:
489
            ROS_INFO("USE_SAFE_CONTROLLER Command received");
490
491
492
493
494
    		loadSafeController();
    		usingSafeController = true;
    		break;

    	case CMD_USE_CUSTOM_CONTROLLER:
495
            ROS_INFO("USE_CUSTOM_CONTROLLER Command received");
496
497
498
499
    		loadCustomController();
    		usingSafeController = false;
    		break;

500
    	case CMD_CRAZYFLY_TAKE_OFF:
501
502
503
504
            if(flying_state == STATE_MOTORS_OFF)
            {
                changeFlyingStateTo(STATE_TAKE_OFF);
            }
505
506
    		break;

507
    	case CMD_CRAZYFLY_LAND:
508
509
510
511
            if(flying_state != STATE_MOTORS_OFF)
            {
                changeFlyingStateTo(STATE_LAND);
            }
512
    		break;
513
514
515
        case CMD_CRAZYFLY_MOTORS_OFF:
            changeFlyingStateTo(STATE_MOTORS_OFF);
            break;
516

517
518
519
    	default:
    		ROS_ERROR_STREAM("unexpected command number: " << cmd);
    		break;
520
	}
521
522
}

523
524
525
526
527
void DBChangedCallback(const std_msgs::Int32& msg)
{
    loadCrazyflieContext();
}

528
529
530
531
532
void crazyRadioStatusCallback(const std_msgs::Int32& msg)
{
    crazyradio_status = msg.data;
}

533
534
535
536
537
538
539
540
541
542
543
544
void controllerSetPointCallback(const Setpoint& newSetpoint)
{
    // load in variable the setpoint
    controller_setpoint = newSetpoint;

    // if we are in flying, set it up NOW
    if(flying_state == STATE_FLYING)
    {
        goToControllerSetpoint();
    }
}

545
546
547
548
549
550
551

void safeYAMLloadedCallback(const std_msgs::Int32& msg)
{
    ROS_INFO("received msg safe loaded YAML");
    loadSafeControllerParameters();
}

552
553
int main(int argc, char* argv[])
{
554
555
	ros::init(argc, argv, "PPSClient");
	ros::NodeHandle nodeHandle("~");
556
557
    ros_namespace = ros::this_node::getNamespace();

558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
    // load default setpoint
    std::vector<float> default_setpoint(4);
    ros::NodeHandle nh_safeControllerService(ros_namespace + "/SafeControllerService");

    ROS_INFO_STREAM(ros_namespace << "/SafeControllerService");

    if(!nh_safeControllerService.getParam("defaultSetpoint", default_setpoint))
    {
        ROS_ERROR_STREAM("couldn't find parameter 'defaultSetpoint'");
    }

    controller_setpoint.x = default_setpoint[0];
    controller_setpoint.y = default_setpoint[1];
    controller_setpoint.z = default_setpoint[2];
    controller_setpoint.yaw = default_setpoint[3];

    // load context parameters
575
	loadParameters(nodeHandle);
576
    loadSafeControllerParameters();
577

578
	//ros::service::waitForService("/CentralManagerService/CentralManager");
579
	centralManager = nodeHandle.serviceClient<CMQuery>("/CentralManagerService/Query", false);
580
	loadCrazyflieContext();
581

582
583
	//keeps 100 messages because otherwise ViconDataPublisher would override the data immediately
	ros::Subscriber viconSubscriber = nodeHandle.subscribe("/ViconDataPublisher/ViconData", 100, viconCallback);
584
	ROS_INFO_STREAM("successfully subscribed to ViconData");
585

586
	//ros::Publishers to advertise the control output
bucyril's avatar
bucyril committed
587
	controlCommandPublisher = nodeHandle.advertise <ControlCommand>("ControlCommand", 1);
phfriedl's avatar
phfriedl committed
588

589
	//this topic lets the PPSClient listen to the terminal commands
590
    commandPublisher = nodeHandle.advertise<std_msgs::Int32>("Command", 1);
bucyril's avatar
bucyril committed
591
    ros::Subscriber commandSubscriber = nodeHandle.subscribe("Command", 1, commandCallback);
phfriedl's avatar
phfriedl committed
592

593
    //this topic lets us use the terminal to communicate with crazyRadio node.
594
    crazyRadioCommandPublisher = nodeHandle.advertise<std_msgs::Int32>("crazyRadioCommand", 1);
595

596
597
    // this topic will publish flying state whenever it changes.
    flyingStatePublisher = nodeHandle.advertise<std_msgs::Int32>("flyingState", 1);
598

599
600
    // crazy radio status
    crazyradio_status = DISCONNECTED;
601

602
603
604
605
606
    // publish first flying state data
    std_msgs::Int32 flying_state_msg;
    flying_state_msg.data = flying_state;
    flyingStatePublisher.publish(flying_state_msg);

607
608
609
    // SafeControllerServicePublisher:
    ros::NodeHandle namespaceNodeHandle = ros::NodeHandle();
    safeControllerServiceSetpointPublisher = namespaceNodeHandle.advertise<d_fall_pps::Setpoint>("SafeControllerService/Setpoint", 1);
610
    ros::Subscriber controllerSetpointSubscriber = namespaceNodeHandle.subscribe("student_GUI/ControllerSetpoint", 1, controllerSetPointCallback);
611

612
    // subscriber for DBChanged
613
    ros::Subscriber DBChangedSubscriber = namespaceNodeHandle.subscribe("/my_GUI/DBChanged", 1, DBChangedCallback);
614

615
616
617
    // crazyradio status. Connected, connecting or disconnected
    ros::Subscriber crazyRadioStatusSubscriber = namespaceNodeHandle.subscribe("CrazyRadio/CrazyRadioStatus", 1, crazyRadioStatusCallback);

618
619
    ros::Subscriber safeYAMloadedSubscriber = namespaceNodeHandle.subscribe("student_GUI/safeYAMLloaded", 1, safeYAMLloadedCallback);

620
	//start with safe controller
621
    flying_state = STATE_MOTORS_OFF;
622
623
	usingSafeController = true;
	loadSafeController();
624

muelmarc's avatar
muelmarc committed
625
626
627
	std::string package_path;
	package_path = ros::package::getPath("d_fall_pps") + "/";
	ROS_INFO_STREAM(package_path);
628
	std::string record_file = package_path + "LoggingPPSClient.bag";
muelmarc's avatar
muelmarc committed
629
630
	bag.open(record_file, rosbag::bagmode::Write);

631
    ros::spin();
muelmarc's avatar
muelmarc committed
632
	bag.close();
633
    return 0;
634
}