Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpRobotBebop2.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Interface for Parrot Bebop 2 drone.
32 *
33 * Authors:
34 * Gatien Gaumerais
35 */
36
37#include <visp3/core/vpConfig.h>
38
39#ifdef VISP_HAVE_ARSDK
40
41#include <visp3/robot/vpRobotBebop2.h>
42
43#include <visp3/core/vpExponentialMap.h> // For velocity computation
44
45#ifdef VISP_HAVE_FFMPEG
46extern "C" {
47#include <libavcodec/avcodec.h>
48#include <libavformat/avformat.h>
49#include <libavutil/imgutils.h>
50}
51#include <visp3/core/vpImageConvert.h>
52#endif
53
54#include <iostream>
55#include <math.h>
56
57#define TAG "vpRobotBebop2" // For error messages of ARSDK
58
72
74bool vpRobotBebop2::m_running = false;
75ARCONTROLLER_Device_t *vpRobotBebop2::m_deviceController = nullptr;
76
112vpRobotBebop2::vpRobotBebop2(bool verbose, bool setDefaultSettings, std::string ipAddress, int discoveryPort)
113 : m_ipAddress(ipAddress), m_discoveryPort(discoveryPort)
114{
115 // Setting up signal handling
116 memset(&m_sigAct, 0, sizeof(m_sigAct));
117 m_sigAct.sa_handler = vpRobotBebop2::sighandler;
118 sigaction(SIGINT, &m_sigAct, 0);
119 sigaction(SIGBUS, &m_sigAct, 0);
120 sigaction(SIGSEGV, &m_sigAct, 0);
121 sigaction(SIGKILL, &m_sigAct, 0);
122 sigaction(SIGQUIT, &m_sigAct, 0);
123
124#ifdef VISP_HAVE_FFMPEG
125 m_codecContext = nullptr;
126 m_packet = nullptr;
127 m_picture = nullptr;
128 m_bgr_picture = nullptr;
129 m_img_convert_ctx = nullptr;
130 m_buffer = nullptr;
131 m_videoDecodingStarted = false;
132#endif
133
134 m_batteryLevel = 100;
135
136 m_exposureSet = true;
137 m_flatTrimFinished = true;
138 m_relativeMoveEnded = true;
139 m_videoResolutionSet = true;
140 m_streamingStarted = false;
141 m_streamingModeSet = false;
142 m_settingsReset = false;
143
144 m_update_codec_params = false;
145 m_codec_params_data = std::vector<uint8_t>();
146
147 m_maxTilt = -1;
148
149 m_cameraHorizontalFOV = -1;
150 m_currentCameraTilt = -1;
151 m_minCameraTilt = -1;
152 m_maxCameraTilt = -1;
153 m_currentCameraPan = -1;
154 m_minCameraPan = -1;
155 m_maxCameraPan = -1;
156
157 setVerbose(verbose);
158
159 m_errorController = ARCONTROLLER_OK;
160 m_deviceState = ARCONTROLLER_DEVICE_STATE_MAX;
161
162 // Initialises a semaphore
163 ARSAL_Sem_Init(&(m_stateSem), 0, 0);
164
165 // Creates a discovery device to find the drone on the wifi network
166 ARDISCOVERY_Device_t *discoverDevice = discoverDrone();
167
168 // Creates a drone controller with the discovery device
169 createDroneController(discoverDevice);
170
171 // Sets up callbacks
172 setupCallbacks();
173
174 // Start the drone controller, connects to the drone. If an error occurs, it will set m_errorController to the error.
175 startController();
176
177 // We check if the drone was actually found and connected to the controller
178 if ((m_errorController != ARCONTROLLER_OK) || (m_deviceState != ARCONTROLLER_DEVICE_STATE_RUNNING)) {
179 cleanUp();
180 m_running = false;
181
183 "Failed to connect to bebop2 with ip %s and port %d. Make sure that the ip address is correct "
184 "and that your computer is connected to the drone Wifi spot before starting",
185 ipAddress.c_str(), discoveryPort));
186 }
187 else {
188 m_running = true;
189
190#ifdef VISP_HAVE_FFMPEG
192#endif
193 if (setDefaultSettings) {
195
196 setMaxTilt(10);
197
198#ifdef VISP_HAVE_FFMPEG
200 setExposure(0);
202#endif
203 setCameraOrientation(0, 0, true);
204 }
205 }
206}
207
214
222{
223 if (isRunning() && m_deviceController != nullptr && isLanded()) {
224
225 m_flatTrimFinished = false;
226
227 m_deviceController->aRDrone3->sendPilotingFlatTrim(m_deviceController->aRDrone3);
228
229 // m_flatTrimFinished is set back to true when the drone has finished the calibration, via a callback
230 while (!m_flatTrimFinished) {
232 }
233 }
234 else {
235 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't do a flat trim : drone isn't landed.");
236 }
237}
238
243std::string vpRobotBebop2::getIpAddress() { return m_ipAddress; }
244
249int vpRobotBebop2::getDiscoveryPort() { return m_discoveryPort; }
250
255double vpRobotBebop2::getMaxTilt() { return m_maxTilt; }
256
263unsigned int vpRobotBebop2::getBatteryLevel() { return m_batteryLevel; }
264
269double vpRobotBebop2::getCameraHorizontalFOV() const { return m_cameraHorizontalFOV; }
270
275double vpRobotBebop2::getCurrentCameraTilt() const { return m_currentCameraTilt; }
276
281double vpRobotBebop2::getMinCameraTilt() const { return m_minCameraTilt; }
282
287double vpRobotBebop2::getMaxCameraTilt() const { return m_maxCameraTilt; }
288
293double vpRobotBebop2::getCurrentCameraPan() const { return m_currentCameraPan; }
294
299double vpRobotBebop2::getMinCameraPan() const { return m_minCameraPan; }
300
305double vpRobotBebop2::getMaxCameraPan() const { return m_maxCameraPan; }
306
319void vpRobotBebop2::setCameraOrientation(double tilt, double pan, bool blocking)
320{
321 if (isRunning() && m_deviceController != nullptr) {
322
323 m_deviceController->aRDrone3->sendCameraOrientationV2(m_deviceController->aRDrone3, static_cast<float>(tilt),
324 static_cast<float>(pan));
325
326 if (blocking) {
327 while (std::abs(tilt - m_currentCameraTilt) > 0.01 || std::abs(pan - m_currentCameraPan) > 0.01) {
329 }
330 }
331
332 }
333 else {
334 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set camera orientation : drone isn't running.");
335 }
336}
337
349void vpRobotBebop2::setCameraTilt(double tilt, bool blocking)
350{
351 if (isRunning() && m_deviceController != nullptr) {
352
353 m_deviceController->aRDrone3->sendCameraOrientationV2(m_deviceController->aRDrone3, static_cast<float>(tilt),
354 static_cast<float>(getCurrentCameraPan()));
355
356 if (blocking) {
357 while (std::abs(tilt - m_currentCameraTilt) > 0.01) {
359 }
360 }
361
362 }
363 else {
364 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set camera tilt value : drone isn't running.");
365 }
366}
367
379void vpRobotBebop2::setCameraPan(double pan, bool blocking)
380{
381 if (isRunning() && m_deviceController != nullptr) {
382
383 m_deviceController->aRDrone3->sendCameraOrientationV2(
384 m_deviceController->aRDrone3, static_cast<float>(getCurrentCameraTilt()), static_cast<float>(pan));
385
386 if (blocking) {
387 while (std::abs(pan - m_currentCameraPan) > 0.01) {
389 }
390 }
391
392 }
393 else {
394 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set camera pan value : drone isn't running.");
395 }
396}
397
403{
404 if (m_deviceController == nullptr) {
405 return false;
406 }
407 else {
408 return m_running;
409 }
410}
411
417{
418#ifdef VISP_HAVE_FFMPEG
419 return m_videoDecodingStarted;
420#else
421 return false;
422#endif
423}
424
430{
431 return getFlyingState() == ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_HOVERING;
432}
433
439{
440 return getFlyingState() == ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_FLYING;
441}
442
448{
449 return getFlyingState() == ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_LANDED;
450}
451
459void vpRobotBebop2::takeOff(bool blocking)
460{
461 if (isRunning() && isLanded() && m_deviceController != nullptr) {
462
463 m_deviceController->aRDrone3->sendPilotingTakeOff(m_deviceController->aRDrone3);
464
465 if (blocking) {
466 while (!isHovering()) {
468 }
469 }
470
471 }
472 else {
473 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't take off : drone isn't landed.");
474 }
475}
476
484{
485 if (m_deviceController != nullptr) {
486 m_deviceController->aRDrone3->sendPilotingLanding(m_deviceController->aRDrone3);
487 }
488}
489
501{
502 if (isRunning() && m_deviceController != nullptr && (isFlying() || isHovering())) {
503 m_errorController =
504 m_deviceController->aRDrone3->setPilotingPCMDGaz(m_deviceController->aRDrone3, static_cast<char>(value));
505
506 if (m_errorController != ARCONTROLLER_OK) {
507 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error when sending move command : %s",
508 ARCONTROLLER_Error_ToString(m_errorController));
509 }
510
511 }
512 else {
513 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set vertical speed : drone isn't flying or hovering.");
514 }
515}
516
528{
529 if (isRunning() && m_deviceController != nullptr && (isFlying() || isHovering())) {
530
531 m_errorController =
532 m_deviceController->aRDrone3->setPilotingPCMDYaw(m_deviceController->aRDrone3, static_cast<char>(value));
533
534 if (m_errorController != ARCONTROLLER_OK) {
535 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error when sending move command : %s",
536 ARCONTROLLER_Error_ToString(m_errorController));
537 }
538
539 }
540 else {
541 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set yaw speed : drone isn't flying or hovering.");
542 }
543}
544
556{
557 if (isRunning() && m_deviceController != nullptr && (isFlying() || isHovering())) {
558
559 m_errorController =
560 m_deviceController->aRDrone3->setPilotingPCMDPitch(m_deviceController->aRDrone3, static_cast<char>(value));
561 m_errorController = m_deviceController->aRDrone3->setPilotingPCMDFlag(m_deviceController->aRDrone3, 1);
562
563 if (m_errorController != ARCONTROLLER_OK) {
564 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error when sending move command : %s",
565 ARCONTROLLER_Error_ToString(m_errorController));
566 }
567
568 }
569 else {
570 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set pitch value : drone isn't flying or hovering.");
571 }
572}
573
585{
586 if (isRunning() && m_deviceController != nullptr && (isFlying() || isHovering())) {
587
588 m_errorController =
589 m_deviceController->aRDrone3->setPilotingPCMDRoll(m_deviceController->aRDrone3, static_cast<char>(value));
590 m_errorController = m_deviceController->aRDrone3->setPilotingPCMDFlag(m_deviceController->aRDrone3, 1);
591
592 if (m_errorController != ARCONTROLLER_OK) {
593 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error when sending move command : %s",
594 ARCONTROLLER_Error_ToString(m_errorController));
595 }
596
597 }
598 else {
599 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set roll value : drone isn't flying or hovering.");
600 }
601}
602
610{
611 if (m_deviceController != nullptr) {
612 m_errorController = m_deviceController->aRDrone3->sendPilotingEmergency(m_deviceController->aRDrone3);
613 }
614}
615
631void vpRobotBebop2::setPosition(float dX, float dY, float dZ, float dPsi, bool blocking)
632{
633 if (isRunning() && m_deviceController != nullptr && (isFlying() || isHovering())) {
634
635 m_relativeMoveEnded = false;
636 m_deviceController->aRDrone3->sendPilotingMoveBy(m_deviceController->aRDrone3, dX, dY, dZ, dPsi);
637
638 if (blocking) {
639
640 // m_relativeMoveEnded is set back to true when the drone has finished his move, via a callback
641 while (!m_relativeMoveEnded) {
643 }
644 }
645 }
646 else {
647 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't move : drone isn't flying or hovering.");
648 }
649}
650
665{
666 double epsilon = (std::numeric_limits<double>::epsilon());
667 if (std::abs(M.getRotationMatrix().getThetaUVector()[0]) >= epsilon) {
668 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't move : rotation around X axis should be 0.");
669 return;
670 }
671 if (std::abs(M.getRotationMatrix().getThetaUVector()[1]) >= epsilon) {
672 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't move : rotation around Y axis should be 0.");
673 return;
674 }
675 float dThetaZ = static_cast<float>(M.getRotationMatrix().getThetaUVector()[2]);
677 setPosition(static_cast<float>(t[0]), static_cast<float>(t[1]), static_cast<float>(t[2]), dThetaZ, blocking);
678}
679
691void vpRobotBebop2::setVelocity(const vpColVector &vel_cmd, double delta_t)
692{
693
694 if (vel_cmd.size() != 4) {
695 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR",
696 "Can't set velocity : dimension of the velocity vector should be equal to 4.");
697 stopMoving();
698 return;
699 }
700
701 vpColVector ve(6);
702
703 ve[0] = vel_cmd[0];
704 ve[1] = vel_cmd[1];
705 ve[2] = vel_cmd[2];
706 ve[5] = vel_cmd[3];
707
709 setPosition(M, false);
710}
711
721{
722 if (verbose) {
723 ARSAL_Print_SetMinimumLevel(ARSAL_PRINT_INFO);
724 }
725 else {
726 ARSAL_Print_SetMinimumLevel(ARSAL_PRINT_WARNING);
727 }
728}
729
735{
736 if (isRunning() && m_deviceController != nullptr) {
737
738 m_settingsReset = false;
739 m_deviceController->common->sendSettingsReset(m_deviceController->common);
740
741 while (!m_settingsReset) {
743 }
744
745 }
746 else {
747 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't reset drone settings : drone isn't running.");
748 }
749}
750
762void vpRobotBebop2::setMaxTilt(double maxTilt)
763{
764 if (isRunning() && m_deviceController != nullptr) {
765 m_deviceController->aRDrone3->sendPilotingSettingsMaxTilt(m_deviceController->aRDrone3,
766 static_cast<float>(maxTilt));
767 }
768 else {
769 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set tilt value : drone isn't running.");
770 }
771}
772
781{
782 if (isRunning() && !isLanded() && m_deviceController != nullptr) {
783 m_errorController = m_deviceController->aRDrone3->setPilotingPCMD(m_deviceController->aRDrone3, 0, 0, 0, 0, 0, 0);
784 }
785}
786
787//*** ***//
788//*** Streaming functions ***//
789//*** ***//
790
791#ifdef VISP_HAVE_FFMPEG // Functions related to video streaming and decoding requiers FFmpeg
792
802{
803 if (m_videoDecodingStarted) {
804
805 if (m_bgr_picture->data[0] != nullptr) {
806 I.resize(static_cast<unsigned int>(m_videoHeight), static_cast<unsigned int>(m_videoWidth));
807
808 m_bgr_picture_mutex.lock();
809 vpImageConvert::BGRToGrey(m_bgr_picture->data[0], reinterpret_cast<unsigned char *>(I.bitmap), I.getWidth(),
810 I.getHeight());
811 m_bgr_picture_mutex.unlock();
812 }
813 else {
814 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Error while getting current grayscale image : image data is nullptr");
815 }
816
817 }
818 else {
819 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't get current image : video streaming isn't started.");
820 }
821}
822
832{
833 if (m_videoDecodingStarted) {
834
835 if (m_bgr_picture->data[0] != nullptr) {
836 I.resize(static_cast<unsigned int>(m_videoHeight), static_cast<unsigned int>(m_videoWidth));
837
838 m_bgr_picture_mutex.lock();
839 vpImageConvert::BGRToRGBa(m_bgr_picture->data[0], reinterpret_cast<unsigned char *>(I.bitmap), I.getWidth(),
840 I.getHeight());
841 m_bgr_picture_mutex.unlock();
842 }
843 else {
844 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Error while getting current RGBa image : image data is nullptr");
845 }
846
847 }
848 else {
849 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't get current image : video streaming isn't started.");
850 }
851}
852
858int vpRobotBebop2::getVideoHeight() { return m_videoHeight; }
859
865int vpRobotBebop2::getVideoWidth() { return m_videoWidth; }
866
875{
876 if (isRunning() && m_deviceController != nullptr) {
877 expo = std::min<float>(1.5f, std::max<float>(-1.5f, expo));
878
879 m_exposureSet = false;
880 m_deviceController->aRDrone3->sendPictureSettingsExpositionSelection(m_deviceController->aRDrone3, expo);
881
882 // m_exposureSet is set back to true when the drone has finished his move, via a callback
883 while (!m_exposureSet) {
885 }
886 }
887 else {
888 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set exposure : drone isn't running.");
889 }
890}
891
907{
908 if (isRunning() && m_deviceController != nullptr) {
909
910 if (!isStreaming() && isLanded()) {
911 eARCOMMANDS_ARDRONE3_MEDIASTREAMING_VIDEOSTREAMMODE_MODE cmd_mode =
912 ARCOMMANDS_ARDRONE3_MEDIASTREAMING_VIDEOSTREAMMODE_MODE_LOW_LATENCY;
913 switch (mode) {
914 case 0:
915 cmd_mode = ARCOMMANDS_ARDRONE3_MEDIASTREAMING_VIDEOSTREAMMODE_MODE_LOW_LATENCY;
916 break;
917 case 1:
918 cmd_mode = ARCOMMANDS_ARDRONE3_MEDIASTREAMING_VIDEOSTREAMMODE_MODE_HIGH_RELIABILITY;
919 break;
920 case 2:
921 cmd_mode = ARCOMMANDS_ARDRONE3_MEDIASTREAMING_VIDEOSTREAMMODE_MODE_HIGH_RELIABILITY_LOW_FRAMERATE;
922 break;
923 default:
924 break;
925 }
926 m_streamingModeSet = false;
927 m_deviceController->aRDrone3->sendMediaStreamingVideoStreamMode(m_deviceController->aRDrone3, cmd_mode);
928
929 // m_streamingModeSet is set back to true when the drone has finished setting the stream mode, via a callback
930 while (!m_streamingModeSet) {
932 }
933
934 }
935 else {
936 ARSAL_PRINT(
937 ARSAL_PRINT_ERROR, "ERROR",
938 "Can't set streaming mode : drone has to be landed and not streaming in order to set streaming mode.");
939 }
940 }
941 else {
942 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set streaming mode : drone isn't running.");
943 }
944}
945
958{
959 if (isRunning() && m_deviceController != nullptr) {
960
961 if (!isStreaming() && isLanded()) {
962
963 eARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEORESOLUTIONS_TYPE cmd_mode;
964
965 switch (mode) {
966
967 case 0:
968 default:
969 cmd_mode = ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEORESOLUTIONS_TYPE_REC1080_STREAM480;
970 m_videoWidth = 856;
971 m_videoHeight = 480;
972 break;
973
974 case 1:
975 cmd_mode = ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEORESOLUTIONS_TYPE_REC720_STREAM720;
976 m_videoWidth = 1280;
977 m_videoHeight = 720;
978 break;
979 }
980
981 m_videoResolutionSet = false;
982 m_deviceController->aRDrone3->sendPictureSettingsVideoResolutions(m_deviceController->aRDrone3, cmd_mode);
983
984 // m_videoResolutionSet is set back to true when the drone has finished setting the resolution, via a callback
985 while (!m_videoResolutionSet) {
987 }
988
989 }
990 else {
991 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR",
992 "Can't set video resolution : drone has to be landed and not streaming in order to set streaming "
993 "parameters.");
994 }
995 }
996 else {
997 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set video resolution : drone isn't running.");
998 }
999}
1000
1013{
1014 if (isRunning() && m_deviceController != nullptr) {
1015
1016 eARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEOSTABILIZATIONMODE_MODE cmd_mode =
1017 ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEOSTABILIZATIONMODE_MODE_NONE;
1018 switch (mode) {
1019
1020 case 0:
1021 cmd_mode = ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEOSTABILIZATIONMODE_MODE_NONE;
1022 break;
1023 case 1:
1024 cmd_mode = ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEOSTABILIZATIONMODE_MODE_ROLL;
1025 break;
1026 case 2:
1027 cmd_mode = ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEOSTABILIZATIONMODE_MODE_PITCH;
1028 break;
1029 case 3:
1030 cmd_mode = ARCOMMANDS_ARDRONE3_PICTURESETTINGS_VIDEOSTABILIZATIONMODE_MODE_ROLL_PITCH;
1031 break;
1032
1033 default:
1034 break;
1035 }
1036 m_deviceController->aRDrone3->sendPictureSettingsVideoStabilizationMode(m_deviceController->aRDrone3, cmd_mode);
1037
1038 }
1039 else {
1040 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't set video stabilisation mode : drone isn't running.");
1041 }
1042}
1043
1053{
1054 if (isRunning() && m_deviceController != nullptr) {
1055 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Starting video streaming ... ");
1056
1057 // Sending command to the drone to start the video stream
1058 m_errorController = m_deviceController->aRDrone3->sendMediaStreamingVideoEnable(m_deviceController->aRDrone3, 1);
1059
1060 if (m_errorController == ARCONTROLLER_OK) {
1061 m_streamingStarted = false;
1062 // Blocking until streaming is started
1063 while (!m_streamingStarted) {
1064 vpTime::sleepMs(1);
1065 }
1066 startVideoDecoding();
1067
1068 /* We wait for the streaming to actually start (it has a delay before actually
1069 sending frames, even if it is indicated as started by the drone), or else the
1070 decoder is doesn't have time to synchronize with the stream */
1071 vpTime::sleepMs(4000);
1072
1073 }
1074 else {
1075 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error :%s", ARCONTROLLER_Error_ToString(m_errorController));
1076 }
1077
1078 }
1079 else {
1080 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't start streaming : drone isn't running.");
1081 }
1082}
1083
1090{
1091 if (m_videoDecodingStarted && m_deviceController != nullptr) {
1092 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Stopping video streaming ... ");
1093
1094 // Sending command to the drone to stop the video stream
1095 m_errorController = m_deviceController->aRDrone3->sendMediaStreamingVideoEnable(m_deviceController->aRDrone3, 0);
1096
1097 if (m_errorController == ARCONTROLLER_OK) {
1098
1099 // Blocking until streaming is stopped
1100 while (getStreamingState() != ARCOMMANDS_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED_DISABLED) {
1101 vpTime::sleepMs(1);
1102 }
1103 vpTime::sleepMs(500); // We wait for the streaming to actually stops or else it causes segmentation fault.
1104 stopVideoDecoding();
1105
1106 }
1107 else {
1108 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error :%s", ARCONTROLLER_Error_ToString(m_errorController));
1109 }
1110
1111 }
1112 else {
1113 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Can't stop streaming : streaming already stopped.");
1114 }
1115}
1116
1117#endif // #ifdef VISP_HAVE_FFMPEG
1118
1119//*** ***//
1120//*** Private Functions ***//
1121//*** ***//
1122
1127void vpRobotBebop2::sighandler(int signo)
1128{
1129 std::cout << "Stopping Bebop2 because of detected signal (" << signo << "): " << static_cast<char>(7);
1130 switch (signo) {
1131 case SIGINT:
1132 std::cout << "SIGINT (stopped by ^C) " << std::endl;
1133 break;
1134 case SIGBUS:
1135 std::cout << "SIGBUS (stopped due to a bus error) " << std::endl;
1136 break;
1137 case SIGSEGV:
1138 std::cout << "SIGSEGV (stopped due to a segmentation fault) " << std::endl;
1139 break;
1140 case SIGKILL:
1141 std::cout << "SIGKILL (stopped by CTRL \\) " << std::endl;
1142 break;
1143 case SIGQUIT:
1144 std::cout << "SIGQUIT " << std::endl;
1145 break;
1146 default:
1147 std::cout << signo << std::endl;
1148 }
1149
1150 vpRobotBebop2::m_running = false;
1151
1152 // Landing the drone
1153 if (m_deviceController != nullptr) {
1154 m_deviceController->aRDrone3->sendPilotingLanding(m_deviceController->aRDrone3);
1155 }
1156 std::exit(EXIT_FAILURE);
1157}
1158
1163eARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE vpRobotBebop2::getFlyingState()
1164{
1165 if (m_deviceController != nullptr) {
1166 eARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE flyingState =
1167 ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_MAX;
1168 eARCONTROLLER_ERROR error;
1169
1170 ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary = ARCONTROLLER_ARDrone3_GetCommandElements(
1171 m_deviceController->aRDrone3, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED, &error);
1172
1173 if (error == ARCONTROLLER_OK && elementDictionary != nullptr) {
1174 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1175 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1176
1177 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1178
1179 if (element != nullptr) {
1180 // Suppress warnings
1181 // Get the value
1182 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE,
1183 arg);
1184
1185 if (arg != nullptr) {
1186 // Enums are stored as I32
1187 flyingState = static_cast<eARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE>(arg->value.I32);
1188 }
1189 }
1190 }
1191 return flyingState;
1192 }
1193 else {
1194 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Error when checking flying state : drone isn't connected.");
1195 return ARCOMMANDS_ARDRONE3_PILOTINGSTATE_FLYINGSTATECHANGED_STATE_MAX;
1196 }
1197}
1198
1203eARCOMMANDS_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED vpRobotBebop2::getStreamingState()
1204{
1205 if (m_deviceController != nullptr) {
1206 eARCOMMANDS_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED streamingState =
1207 ARCOMMANDS_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED_MAX;
1208 eARCONTROLLER_ERROR error;
1209
1210 ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary = ARCONTROLLER_ARDrone3_GetCommandElements(
1211 m_deviceController->aRDrone3, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED,
1212 &error);
1213
1214 if (error == ARCONTROLLER_OK && elementDictionary != nullptr) {
1215 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1216 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1217
1218 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1219
1220 if (element != nullptr) {
1221 // Get the value
1222 HASH_FIND_STR(element->arguments,
1223 ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED, arg);
1224
1225 if (arg != nullptr) {
1226 // Enums are stored as I32
1227 streamingState =
1228 static_cast<eARCOMMANDS_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED>(arg->value.I32);
1229 }
1230 }
1231 }
1232 return streamingState;
1233 }
1234 else {
1235 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Error when checking streaming state : drone isn't connected.");
1236 return ARCOMMANDS_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED_ENABLED_MAX;
1237 }
1238}
1239
1244ARDISCOVERY_Device_t *vpRobotBebop2::discoverDrone()
1245{
1246 eARDISCOVERY_ERROR errorDiscovery = ARDISCOVERY_OK;
1247
1248 ARDISCOVERY_Device_t *device = ARDISCOVERY_Device_New(&errorDiscovery);
1249
1250 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Starting drone Wifi discovery ...");
1251 const char *charIpAddress = m_ipAddress.c_str();
1252 errorDiscovery =
1253 ARDISCOVERY_Device_InitWifi(device, ARDISCOVERY_PRODUCT_BEBOP_2, "bebop2", charIpAddress, m_discoveryPort);
1254
1255 if (errorDiscovery != ARDISCOVERY_OK) {
1256 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Discovery error :%s", ARDISCOVERY_Error_ToString(errorDiscovery));
1257 }
1258 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Drone controller created.");
1259 return device;
1260}
1261
1268void vpRobotBebop2::createDroneController(ARDISCOVERY_Device_t *discoveredDrone)
1269{
1270 m_deviceController = ARCONTROLLER_Device_New(discoveredDrone, &m_errorController);
1271 if (m_errorController != ARCONTROLLER_OK) {
1272 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Creation of deviceController failed.");
1273 }
1274 ARDISCOVERY_Device_Delete(&discoveredDrone);
1275 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Device created.");
1276}
1277
1282void vpRobotBebop2::setupCallbacks()
1283{
1284 // Adding stateChanged callback, called when the state of the controller has changed
1285 m_errorController = ARCONTROLLER_Device_AddStateChangedCallback(m_deviceController, stateChangedCallback, this);
1286 if (m_errorController != ARCONTROLLER_OK) {
1287 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "add State callback failed.");
1288 }
1289
1290 // Adding commendReceived callback, called when the a command has been received from the device
1291 m_errorController = ARCONTROLLER_Device_AddCommandReceivedCallback(m_deviceController, commandReceivedCallback, this);
1292
1293 if (m_errorController != ARCONTROLLER_OK) {
1294 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "add Command callback failed.");
1295 }
1296
1297#ifdef VISP_HAVE_FFMPEG
1298 // Adding frame received callback, called when a streaming frame has been received from the device
1299 m_errorController = ARCONTROLLER_Device_SetVideoStreamCallbacks(m_deviceController, decoderConfigCallback,
1300 didReceiveFrameCallback, nullptr, this);
1301
1302 if (m_errorController != ARCONTROLLER_OK) {
1303 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error: %s", ARCONTROLLER_Error_ToString(m_errorController));
1304 }
1305#endif
1306 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Callbacks set up.");
1307}
1308
1313void vpRobotBebop2::startController()
1314{
1315 // Starts the controller
1316 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Connecting ...");
1317 m_errorController = ARCONTROLLER_Device_Start(m_deviceController);
1318
1319 if (m_errorController != ARCONTROLLER_OK) {
1320 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error :%s", ARCONTROLLER_Error_ToString(m_errorController));
1321 }
1322
1323 // Waits for the stateChangedCallback to unclock the semaphore
1324 ARSAL_Sem_Wait(&(m_stateSem));
1325
1326 // Checks the device state
1327 m_deviceState = ARCONTROLLER_Device_GetState(m_deviceController, &m_errorController);
1328
1329 if ((m_errorController != ARCONTROLLER_OK) || (m_deviceState != ARCONTROLLER_DEVICE_STATE_RUNNING)) {
1330 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- deviceState :%d", m_deviceState);
1331 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "- error :%s", ARCONTROLLER_Error_ToString(m_errorController));
1332 }
1333 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Controller started.");
1334}
1335
1336#ifdef VISP_HAVE_FFMPEG
1342void vpRobotBebop2::initCodec()
1343{
1344 // av_register_all();
1345 // avcodec_register_all();
1346 avformat_network_init();
1347
1348 // Finds the correct codec
1349 const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
1350 if (!codec) {
1351 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Codec not found.");
1352 return;
1353 }
1354
1355 // Allocates memory for codec
1356 m_codecContext = avcodec_alloc_context3(codec);
1357
1358 if (!m_codecContext) {
1359 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Failed to allocate codec context.");
1360 return;
1361 }
1362
1363 // Sets codec parameters (TODO : should be done automatically by drone callback decoderConfigCallback)
1364 m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
1365 m_codecContext->skip_frame = AVDISCARD_DEFAULT;
1366 m_codecContext->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
1367 m_codecContext->skip_loop_filter = AVDISCARD_DEFAULT;
1368 m_codecContext->workaround_bugs = AVMEDIA_TYPE_VIDEO;
1369 m_codecContext->codec_id = AV_CODEC_ID_H264;
1370 m_codecContext->skip_idct = AVDISCARD_DEFAULT;
1371
1372 m_codecContext->width = m_videoWidth;
1373 m_codecContext->height = m_videoHeight;
1374
1375 // if (codec->capabilities & AV_CODEC_CAP_TRUNCATED) {
1376 // m_codecContext->flags |= AV_CODEC_FLAG_TRUNCATED;
1377 // }
1378 m_codecContext->flags2 |= AV_CODEC_FLAG2_CHUNKS;
1379
1380 // Opens the codec
1381 if (avcodec_open2(m_codecContext, codec, nullptr) < 0) {
1382 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Failed to open codec.");
1383 return;
1384 }
1385
1386 AVPixelFormat pFormat = AV_PIX_FMT_BGR24;
1387 int numBytes = av_image_get_buffer_size(pFormat, m_codecContext->width, m_codecContext->height, 1);
1388 m_buffer = static_cast<uint8_t *>(av_malloc(static_cast<unsigned long>(numBytes) * sizeof(uint8_t)));
1389
1390 //av_init_packet(&m_packet); // Packed used to send data to the decoder
1391 m_packet = av_packet_alloc();
1392 m_picture = av_frame_alloc(); // Frame used to receive data from the decoder
1393
1394 m_bgr_picture_mutex.lock();
1395 m_bgr_picture = av_frame_alloc(); // Frame used to store rescaled frame received from the decoder
1396 m_bgr_picture_mutex.unlock();
1397
1398 m_img_convert_ctx = sws_getContext(m_codecContext->width, m_codecContext->height, m_codecContext->pix_fmt,
1399 m_codecContext->width, m_codecContext->height, pFormat, SWS_BICUBIC, nullptr, nullptr,
1400 nullptr); // Used to rescale frame received from the decoder
1401}
1402
1408void vpRobotBebop2::cleanUpCodec()
1409{
1410 m_videoDecodingStarted = false;
1411 av_packet_unref(m_packet);
1412
1413 if (m_codecContext) {
1414 avcodec_flush_buffers(m_codecContext);
1415 avcodec_free_context(&m_codecContext);
1416 }
1417
1418 if (m_picture) {
1419 av_frame_free(&m_picture);
1420 }
1421 if (m_packet) {
1422 av_packet_free(&m_packet);
1423 }
1424
1425 if (m_bgr_picture) {
1426 m_bgr_picture_mutex.lock();
1427 av_frame_free(&m_bgr_picture);
1428 m_bgr_picture_mutex.unlock();
1429 }
1430
1431 if (m_img_convert_ctx) {
1432 sws_freeContext(m_img_convert_ctx);
1433 }
1434 if (m_buffer) {
1435 av_free(m_buffer);
1436 }
1437}
1438
1444void vpRobotBebop2::startVideoDecoding()
1445{
1446 if (!m_videoDecodingStarted) {
1447 initCodec();
1448 m_videoDecodingStarted = true;
1449 }
1450 else {
1451 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Video decoding is already started.");
1452 }
1453}
1454
1460void vpRobotBebop2::stopVideoDecoding()
1461{
1462 if (m_videoDecodingStarted) {
1463 cleanUpCodec();
1464 }
1465 else {
1466 ARSAL_PRINT(ARSAL_PRINT_ERROR, "ERROR", "Video decoding is already stopped.");
1467 }
1468}
1469
1477void vpRobotBebop2::computeFrame(ARCONTROLLER_Frame_t *frame)
1478{
1479
1480 // Updating codec parameters from SPS and PPS buffers received from the drone in decoderConfigCallback
1481 if (m_update_codec_params && m_codec_params_data.size()) {
1482 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Updating H264 codec parameters (Buffer Size: %lu) ...",
1483 m_codec_params_data.size());
1484
1485 m_packet->data = &m_codec_params_data[0];
1486 m_packet->size = static_cast<int>(m_codec_params_data.size());
1487
1488 int ret = avcodec_send_packet(m_codecContext, m_packet);
1489
1490 if (ret == 0) {
1491
1492 ret = avcodec_receive_frame(m_codecContext, m_picture);
1493
1494 if (ret == 0 || ret == AVERROR(EAGAIN)) {
1495 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "H264 codec parameters updated.");
1496 }
1497 else {
1498 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Unexpected error while updating H264 parameters.");
1499 }
1500 }
1501 else {
1502 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Unexpected error while sending H264 parameters.");
1503 }
1504 m_update_codec_params = false;
1505 av_packet_unref(m_packet);
1506 av_frame_unref(m_picture);
1507 }
1508
1509 // Decoding frame coming from the drone
1510 m_packet->data = frame->data;
1511 m_packet->size = static_cast<int>(frame->used);
1512
1513 int ret = avcodec_send_packet(m_codecContext, m_packet);
1514 if (ret < 0) {
1515
1516 char *errbuff = new char[AV_ERROR_MAX_STRING_SIZE];
1517 av_strerror(ret, errbuff, AV_ERROR_MAX_STRING_SIZE);
1518 std::string err(errbuff);
1519 delete[] errbuff;
1520 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Error sending a packet for decoding : %d, %s", ret, err.c_str());
1521
1522 }
1523 else {
1524
1525 ret = avcodec_receive_frame(m_codecContext, m_picture);
1526
1527 if (ret < 0) {
1528
1529 if (ret == AVERROR(EAGAIN)) {
1530 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "AVERROR(EAGAIN)"); // Not an error, need to send data again
1531 }
1532 else if (ret == AVERROR_EOF) {
1533 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "AVERROR_EOF"); // End of file reached, should not happen with drone footage
1534 }
1535 else {
1536
1537 char *errbuff = new char[AV_ERROR_MAX_STRING_SIZE];
1538 av_strerror(ret, errbuff, AV_ERROR_MAX_STRING_SIZE);
1539 std::string err(errbuff);
1540 delete[] errbuff;
1541 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Error receiving a decoded frame : %d, %s", ret, err.c_str());
1542 }
1543 }
1544 else {
1545 m_bgr_picture_mutex.lock();
1546 av_frame_unref(m_bgr_picture);
1547 av_image_fill_arrays(m_bgr_picture->data, m_bgr_picture->linesize, m_buffer, AV_PIX_FMT_BGR24,
1548 m_codecContext->width, m_codecContext->height, 1);
1549
1550 sws_scale(m_img_convert_ctx, (m_picture)->data, (m_picture)->linesize, 0, m_codecContext->height,
1551 (m_bgr_picture)->data, (m_bgr_picture)->linesize);
1552
1553 m_bgr_picture_mutex.unlock();
1554 }
1555 }
1556
1557 av_packet_unref(m_packet);
1558
1559 av_frame_unref(m_picture);
1560}
1561#endif // #ifdef VISP_HAVE_FFMPEG
1567void vpRobotBebop2::cleanUp()
1568{
1569 if (m_deviceController != nullptr) {
1570 // Lands the drone if not landed
1571 land();
1572
1573#ifdef VISP_HAVE_FFMPEG
1574 // Stops the streaming if not stopped
1575 stopStreaming();
1576#endif
1577
1578 // Deletes the controller
1579 m_deviceState = ARCONTROLLER_Device_GetState(m_deviceController, &m_errorController);
1580 if ((m_errorController == ARCONTROLLER_OK) && (m_deviceState != ARCONTROLLER_DEVICE_STATE_STOPPED)) {
1581
1582 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Disconnecting ...");
1583 m_errorController = ARCONTROLLER_Device_Stop(m_deviceController);
1584
1585 if (m_errorController == ARCONTROLLER_OK) {
1586 // Wait for the semaphore to increment, it will when the controller changes its state to 'stopped'
1587 ARSAL_Sem_Wait(&(m_stateSem));
1588 }
1589 }
1590 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Deleting device controller ...");
1591 ARCONTROLLER_Device_Delete(&m_deviceController);
1592
1593 // Destroys the semaphore
1594 ARSAL_Sem_Destroy(&(m_stateSem));
1595
1596 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "- Cleanup done.");
1597 }
1598 else {
1599
1600 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Error while cleaning up memory.");
1601 }
1602 m_running = false;
1603}
1604
1605//*** ***//
1606//*** Callbacks ***//
1607//*** ***//
1608
1617void vpRobotBebop2::stateChangedCallback(eARCONTROLLER_DEVICE_STATE newState, eARCONTROLLER_ERROR error,
1618 void *customData)
1619{
1620 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Controller state changed, new state: %d.", newState);
1621 (void)error;
1622
1623 vpRobotBebop2 *drone = static_cast<vpRobotBebop2 *>(customData);
1624 switch (newState) {
1625 case ARCONTROLLER_DEVICE_STATE_STOPPED:
1626 // Stopping the programm
1627 drone->m_running = false;
1628 // Incrementing semaphore
1629 ARSAL_Sem_Post(&(drone->m_stateSem));
1630 break;
1631
1632 case ARCONTROLLER_DEVICE_STATE_RUNNING:
1633 // Incrementing semaphore
1634 ARSAL_Sem_Post(&(drone->m_stateSem));
1635 break;
1636
1637 default:
1638 break;
1639 }
1640}
1641
1642#ifdef VISP_HAVE_FFMPEG
1652eARCONTROLLER_ERROR vpRobotBebop2::decoderConfigCallback(ARCONTROLLER_Stream_Codec_t codec, void *customData)
1653{
1654 vpRobotBebop2 *drone = static_cast<vpRobotBebop2 *>(customData);
1655
1656 uint8_t *sps_buffer_ptr = codec.parameters.h264parameters.spsBuffer;
1657 uint32_t sps_buffer_size = static_cast<uint32_t>(codec.parameters.h264parameters.spsSize);
1658 uint8_t *pps_buffer_ptr = codec.parameters.h264parameters.ppsBuffer;
1659 uint32_t pps_buffer_size = static_cast<uint32_t>(codec.parameters.h264parameters.ppsSize);
1660
1661 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "H264 configuration packet received: #SPS: %d #PPS: %d", sps_buffer_size,
1662 pps_buffer_size);
1663
1664 drone->m_update_codec_params = (sps_buffer_ptr && pps_buffer_ptr && sps_buffer_size && pps_buffer_size &&
1665 (pps_buffer_size < 32) && (sps_buffer_size < 32));
1666
1667 if (drone->m_update_codec_params) {
1668 // If codec parameters where received from the drone, we store them to pass them to the decoder in the next call of
1669 // computeFrame
1670 drone->m_codec_params_data.resize(sps_buffer_size + pps_buffer_size);
1671 std::copy(sps_buffer_ptr, sps_buffer_ptr + sps_buffer_size, drone->m_codec_params_data.begin());
1672 std::copy(pps_buffer_ptr, pps_buffer_ptr + pps_buffer_size, drone->m_codec_params_data.begin() + sps_buffer_size);
1673 }
1674 else {
1675 // If data is invalid, we clear the vector
1676 drone->m_codec_params_data.clear();
1677 }
1678 return ARCONTROLLER_OK;
1679}
1680
1689eARCONTROLLER_ERROR vpRobotBebop2::didReceiveFrameCallback(ARCONTROLLER_Frame_t *frame, void *customData)
1690{
1691 vpRobotBebop2 *drone = static_cast<vpRobotBebop2 *>(customData);
1692
1693 if (frame != nullptr) {
1694
1695 if (drone->m_videoDecodingStarted) {
1696 drone->computeFrame(frame);
1697 }
1698
1699 }
1700 else {
1701 ARSAL_PRINT(ARSAL_PRINT_WARNING, TAG, "frame is nullptr.");
1702 }
1703
1704 return ARCONTROLLER_OK;
1705}
1706#endif // #ifdef VISP_HAVE_FFMPEG
1707
1717void vpRobotBebop2::cmdBatteryStateChangedRcv(ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary,
1718 vpRobotBebop2 *drone)
1719{
1720 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1721 ARCONTROLLER_DICTIONARY_ELEMENT_t *singleElement = nullptr;
1722
1723 if (elementDictionary == nullptr) {
1724 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "elements is nullptr");
1725 return;
1726 }
1727
1728 // Get the command received in the device controller
1729 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, singleElement);
1730
1731 if (singleElement == nullptr) {
1732 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "singleElement is nullptr");
1733 return;
1734 }
1735
1736 // Get the value
1737 HASH_FIND_STR(singleElement->arguments, ARCONTROLLER_DICTIONARY_KEY_COMMON_COMMONSTATE_BATTERYSTATECHANGED_PERCENT,
1738 arg);
1739
1740 if (arg == nullptr) {
1741 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "arg is nullptr");
1742 return;
1743 }
1744 drone->m_batteryLevel = arg->value.U8;
1745 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Battery level changed : %u percent remaining.", drone->m_batteryLevel);
1746
1747 if (drone->m_batteryLevel <= 5) {
1748 ARSAL_PRINT(ARSAL_PRINT_WARNING, TAG, " - WARNING, very low battery level, drone will stop soon !");
1749 }
1750 else if (drone->m_batteryLevel <= 10) {
1751 ARSAL_PRINT(ARSAL_PRINT_WARNING, TAG, " - Warning, low battery level !");
1752 }
1753}
1754
1765void vpRobotBebop2::cmdCameraOrientationChangedRcv(ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary,
1766 vpRobotBebop2 *drone)
1767{
1768 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1769 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1770 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1771 if (element != nullptr) {
1772 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_CAMERASTATE_ORIENTATIONV2_TILT, arg);
1773
1774 if (arg != nullptr) {
1775 drone->m_currentCameraTilt = static_cast<double>(arg->value.Float);
1776 }
1777
1778 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_CAMERASTATE_ORIENTATIONV2_PAN, arg);
1779 if (arg != nullptr) {
1780 drone->m_currentCameraPan = static_cast<double>(arg->value.Float);
1781 }
1782 }
1783}
1784
1796void vpRobotBebop2::cmdCameraSettingsRcv(ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary, vpRobotBebop2 *drone)
1797{
1798 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1799 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1800 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1801 if (element != nullptr) {
1802 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_COMMON_CAMERASETTINGSSTATE_CAMERASETTINGSCHANGED_FOV,
1803 arg);
1804 if (arg != nullptr) {
1805 drone->m_cameraHorizontalFOV = static_cast<double>(arg->value.Float);
1806 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Camera horizontal FOV : %f degrees.",
1807 static_cast<double>(drone->m_cameraHorizontalFOV));
1808 }
1809 HASH_FIND_STR(element->arguments,
1810 ARCONTROLLER_DICTIONARY_KEY_COMMON_CAMERASETTINGSSTATE_CAMERASETTINGSCHANGED_PANMAX, arg);
1811 if (arg != nullptr) {
1812 drone->m_maxCameraPan = static_cast<double>(arg->value.Float);
1813 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Max camera pan : %f degrees.",
1814 static_cast<double>(drone->m_maxCameraPan));
1815 }
1816 HASH_FIND_STR(element->arguments,
1817 ARCONTROLLER_DICTIONARY_KEY_COMMON_CAMERASETTINGSSTATE_CAMERASETTINGSCHANGED_PANMIN, arg);
1818 if (arg != nullptr) {
1819 drone->m_minCameraPan = static_cast<double>(arg->value.Float);
1820 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Min camera pan : %f degrees.",
1821 static_cast<double>(drone->m_minCameraPan));
1822 }
1823 HASH_FIND_STR(element->arguments,
1824 ARCONTROLLER_DICTIONARY_KEY_COMMON_CAMERASETTINGSSTATE_CAMERASETTINGSCHANGED_TILTMAX, arg);
1825 if (arg != nullptr) {
1826 drone->m_maxCameraTilt = static_cast<double>(arg->value.Float);
1827 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Max camera tilt : %f degrees.",
1828 static_cast<double>(drone->m_maxCameraTilt));
1829 }
1830 HASH_FIND_STR(element->arguments,
1831 ARCONTROLLER_DICTIONARY_KEY_COMMON_CAMERASETTINGSSTATE_CAMERASETTINGSCHANGED_TILTMIN, arg);
1832 if (arg != nullptr) {
1833 drone->m_minCameraTilt = static_cast<double>(arg->value.Float);
1834 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, " - Min camera tilt : %f degrees.",
1835 static_cast<double>(drone->m_minCameraTilt));
1836 }
1837 }
1838}
1839
1850void vpRobotBebop2::cmdMaxPitchRollChangedRcv(ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary,
1851 vpRobotBebop2 *drone)
1852{
1853 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1854 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1855
1856 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1857 if (element != nullptr) {
1858 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGSETTINGSSTATE_MAXTILTCHANGED_CURRENT,
1859 arg);
1860 if (arg != nullptr) {
1861 drone->m_maxTilt = static_cast<double>(arg->value.Float);
1862 }
1863 }
1864}
1865
1876void vpRobotBebop2::cmdRelativeMoveEndedRcv(ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary, vpRobotBebop2 *drone)
1877{
1878 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1879 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1880
1881 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1882
1883 if (element != nullptr) {
1884 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGEVENT_MOVEBYEND_ERROR, arg);
1885
1886 if (arg != nullptr) {
1887 eARCOMMANDS_ARDRONE3_PILOTINGEVENT_MOVEBYEND_ERROR error =
1888 static_cast<eARCOMMANDS_ARDRONE3_PILOTINGEVENT_MOVEBYEND_ERROR>(arg->value.I32);
1889 if ((error != ARCOMMANDS_ARDRONE3_PILOTINGEVENT_MOVEBYEND_ERROR_OK) &&
1890 (error != ARCOMMANDS_ARDRONE3_PILOTINGEVENT_MOVEBYEND_ERROR_INTERRUPTED)) {
1891 ARSAL_PRINT(ARSAL_PRINT_ERROR, TAG, "Relative move ended with error %d", error);
1892 }
1893 drone->m_relativeMoveEnded = true;
1894 }
1895 }
1896}
1897
1908void vpRobotBebop2::cmdExposureSetRcv(ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary, vpRobotBebop2 *drone)
1909{
1910 ARCONTROLLER_DICTIONARY_ARG_t *arg = nullptr;
1911 ARCONTROLLER_DICTIONARY_ELEMENT_t *element = nullptr;
1912
1913 HASH_FIND_STR(elementDictionary, ARCONTROLLER_DICTIONARY_SINGLE_KEY, element);
1914
1915 if (element != nullptr) {
1916
1917 HASH_FIND_STR(element->arguments, ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PICTURESETTINGSSTATE_EXPOSITIONCHANGED_VALUE,
1918 arg);
1919
1920 if (arg != nullptr) {
1921 drone->m_exposureSet = true;
1922 }
1923 }
1924}
1925
1935void vpRobotBebop2::commandReceivedCallback(eARCONTROLLER_DICTIONARY_KEY commandKey,
1936 ARCONTROLLER_DICTIONARY_ELEMENT_t *elementDictionary, void *customData)
1937{
1938 vpRobotBebop2 *drone = static_cast<vpRobotBebop2 *>(customData);
1939
1940 if (drone == nullptr)
1941 return;
1942
1943 switch (commandKey) {
1944 case ARCONTROLLER_DICTIONARY_KEY_COMMON_COMMONSTATE_BATTERYSTATECHANGED:
1945 // If the command received is a battery state changed
1946 cmdBatteryStateChangedRcv(elementDictionary, drone);
1947 break;
1948
1949 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGSETTINGSSTATE_MAXTILTCHANGED:
1950 // If the command receivend is a max pitch/roll changed
1951 cmdMaxPitchRollChangedRcv(elementDictionary, drone);
1952 break;
1953
1954 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGEVENT_MOVEBYEND:
1955 // If the command received is a relative move ended
1956 cmdRelativeMoveEndedRcv(elementDictionary, drone);
1957 break;
1958
1959 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PILOTINGSTATE_FLATTRIMCHANGED:
1960 // If the command received is a flat trim finished
1961 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Flat trim finished ...");
1962 drone->m_flatTrimFinished = true;
1963 break;
1964
1965 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PICTURESETTINGSSTATE_EXPOSITIONCHANGED:
1966 // If the command received is a exposition changed
1967 cmdExposureSetRcv(elementDictionary, drone);
1968 break;
1969
1970 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_PICTURESETTINGSSTATE_VIDEORESOLUTIONSCHANGED:
1971 // If the command received is a resolution changed
1972 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Video resolution set ...");
1973 drone->m_videoResolutionSet = true;
1974 break;
1975
1976 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOENABLECHANGED:
1977 // If the command received is a streaming started
1978 drone->m_streamingStarted = true;
1979 break;
1980
1981 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_MEDIASTREAMINGSTATE_VIDEOSTREAMMODECHANGED:
1982 // If the command received is a streaming mode changed
1983 drone->m_streamingModeSet = true;
1984 break;
1985
1986 case ARCONTROLLER_DICTIONARY_KEY_COMMON_SETTINGSSTATE_RESETCHANGED:
1987 // If the command received is a settings reset
1988 ARSAL_PRINT(ARSAL_PRINT_INFO, TAG, "Settings reset ...");
1989 drone->m_settingsReset = true;
1990 break;
1991
1992 case ARCONTROLLER_DICTIONARY_KEY_ARDRONE3_CAMERASTATE_ORIENTATIONV2:
1993 // If the command received is a camera orientation changed
1994 cmdCameraOrientationChangedRcv(elementDictionary, drone);
1995 break;
1996
1997 case ARCONTROLLER_DICTIONARY_KEY_COMMON_CAMERASETTINGSSTATE_CAMERASETTINGSCHANGED:
1998 // If the command received is a camera information sent
1999 cmdCameraSettingsRcv(elementDictionary, drone);
2000 break;
2001
2002 default:
2003 break;
2004 }
2005}
2006
2007#undef TAG
2008END_VISP_NAMESPACE
2009#elif !defined(VISP_BUILD_SHARED_LIBS)
2010// Work around to avoid warning: libvisp_robot.a(vpRobotBebop2.cpp.o) has
2011// no symbols
2012void dummy_vpRobotBebop2() { }
2013#endif // VISP_HAVE_ARSDK
unsigned int size() const
Return the number of elements of the 2D array.
Definition vpArray2D.h:435
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ fatalError
Fatal error.
Definition vpException.h:72
static vpHomogeneousMatrix direct(const vpColVector &v)
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpRotationMatrix getRotationMatrix() const
vpTranslationVector getTranslationVector() const
static void BGRToGrey(unsigned char *bgr, unsigned char *grey, unsigned int width, unsigned int height, bool flip=false, unsigned int nThreads=0)
static void BGRToRGBa(unsigned char *bgr, unsigned char *rgba, unsigned int width, unsigned int height, bool flip=false)
Definition of the vpImage class member functions.
Definition vpImage.h:131
void setPitch(int value)
std::string getIpAddress()
double getMinCameraPan() const
void setMaxTilt(double maxTilt)
void setPosition(float dX, float dY, float dZ, float dPsi, bool blocking)
void setVelocity(const vpColVector &vel, double delta_t)
void setExposure(float expo)
double getCurrentCameraPan() const
void setVideoStabilisationMode(int mode)
void setRoll(int value)
double getMinCameraTilt() const
double getMaxCameraTilt() const
void setVerbose(bool verbose)
void setVerticalSpeed(int value)
void getGrayscaleImage(vpImage< unsigned char > &I)
void setStreamingMode(int mode)
static void land()
unsigned int getBatteryLevel()
void getRGBaImage(vpImage< vpRGBa > &I)
void setYawSpeed(int value)
void setCameraPan(double pan, bool blocking=false)
void takeOff(bool blocking=true)
virtual ~vpRobotBebop2()
double getCurrentCameraTilt() const
double getCameraHorizontalFOV() const
void setVideoResolution(int mode)
void setCameraTilt(double tilt, bool blocking=false)
vpRobotBebop2(bool verbose=false, bool setDefaultSettings=true, std::string ipAddress="192.168.42.1", int discoveryPort=44444)
void setCameraOrientation(double tilt, double pan, bool blocking=false)
double getMaxCameraPan() const
vpThetaUVector getThetaUVector()
Class that consider the case of a translation vector.
VISP_EXPORT void sleepMs(double t)