Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add QGC Mission import capability #235

Merged
merged 43 commits into from
Feb 15, 2018
Merged

Conversation

shakthi-prashanth-m
Copy link
Contributor

@shakthi-prashanth-m shakthi-prashanth-m commented Jan 23, 2018

This patch

  • Adds new capability to Mission plugin.
    Now, missions can be imported from QGroundControl plan file. This enables users to create plans on QGroundControl and simply import them into DroneCore applications. We use json11 library for parsing QGC plan files.
  • Adds unit test for import QGC mission feature which tests with a sample QGC plan.
  • Re-factors Fly mission example
  • Adds Fly QGC mission example to demonstrate popular QGC plan.
  • Addresses Rename camera_action_delay_s to loiter_time_s in MissionItem class #249
  • Adds methods to know whether a mission item has position info set.
  • Appveyor fixes for Windows build.
  • Adds QGC Mission Importer which currently handles
    • Takeoff, Land
    • Navigation waypoints
    • Start image capture
      • Take a photo
      • Take a photo at intervals
    • Stop Image capture
    • Start Video capture
    • Stop Video capture
    • Control Gimbal pitch & yaw (MAVLink Triggering)
    • Change speed

@shakthi-prashanth-m
Copy link
Contributor Author

So many errors reported in json11! We better ignore them.

Copy link
Collaborator

@julianoes julianoes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is certainly going in the right direction, I think!

CMakeLists.txt Outdated
@@ -99,6 +99,7 @@ include(autogenerate_plugin_container.cmake)
include_directories(
include
libs/include
libs/json11
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put libs/json11 to the bottom of this list and put a SYSTEM in front of it. This way the warnings are ignored.

LogErr() << "Mission: Unsupported mission command: " << command;
return Mission::Result::UNSUPPORTED_MISSION_CMD;
}
std::cout << "Cmd: " << command << " Lat: " << lat_deg << " Lon: " << lon_deg << " Alt: " <<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use LogDebug() please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I will. Thanks.

}
std::cout << "Cmd: " << command << " Lat: " << lat_deg << " Lon: " << lon_deg << " Alt: " <<
rel_alt_deg <<
" Speed " << speed_m_s << " Is fly thru: " << is_fly_through <<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this print Is fly through: 1 ? Or true and false?

You could do: << (is_fly_through ? "yes" : "no") <<

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot! I will add.

}

// Compose mission items
Mission::Result result = [&items](const Json & mission_json) -> Mission::Result {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this function is too big. It would be better to split it up into logic that reads the file and a parse function.

Copy link
Contributor Author

@shakthi-prashanth-m shakthi-prashanth-m Jan 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even I felt the same. But we need to make them static again! Also we need to add them to mission.h. C-style is to make them static functions. But lets not use C-style. Isn't it ?

Copy link
Contributor Author

@shakthi-prashanth-m shakthi-prashanth-m Jan 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can have whole implementation in MissionImpl class. And lets invoke them via Mission class. Does it make sense ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, move it to MissionImpl and invoke in Mission.

@@ -87,6 +88,13 @@ class MissionItem
NONE /**< @brief No action. */
};

/**
* @brief Converts CamerAction to English strings.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CamerAction -> CameraAction.

gimbal_yaw_deg = params[2];
break;
case MAV_CMD_NAV_WAYPOINT:
is_fly_through = (params[0] == 0.0) ? true : false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no break on purpose?

Copy link
Contributor Author

@shakthi-prashanth-m shakthi-prashanth-m Jan 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Because, param 5,6,7 of both NAV_WAYPOINT & NAV_TAKEOFF require Lat, Long and Alt respectively.

speed_m_s = params[1];
break;
case MAV_CMD_DO_MOUNT_CONTROL:
// Possible bug in QGroundcontrol. It stores -ve values for pitch in deg.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pitch down is - because it's all in the NED frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh! Thanks @julianoes for the clarification.

Copy link
Collaborator

@julianoes julianoes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shakthi-prashanth-m this is looking good, however, such a piece of code really should have a unit test in my opinion.

I suggest you add an example json file and read it in and check the values. This way, when QGC changes the format, we can just update the test file and rerun it and make sure we're still compatible.

gimbal_yaw_deg = params[2];
break;
case MAV_CMD_NAV_WAYPOINT:
is_fly_through = (params[0] == 0.0) ? true : false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing break, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:) Like I said here, its intentional. Param 5,6,7 of both NAV_WAYPOINT & NAV_TAKEOFF need Lat, Long and Alt respectively, so combined them.


// Add mission item to the list
mission_items.push_back([&]() -> std::shared_ptr<MissionItem> const {
std::shared_ptr<MissionItem> new_item(new MissionItem());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of std::shared_ptr<MissionItem> new_item(new MissionItem()); you can do auto new_item = std::make_shared<MissionItem>();.

Copy link
Contributor Author

@shakthi-prashanth-m shakthi-prashanth-m Jan 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@julianoes I agree with you. How about adding integration_tests/mission_qgc.cpp

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be a unit test in my opinion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, you mean as part of integration_tests/mission.cpp ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok! Thanks. I'll add it.

LogWarn() << "Mission: Unsupported mission command: " << command << ". Ignoring.";
break;
}
// Maybe removed
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe what? 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that we can remove debug log if its annoying for larger mission. :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand but it's a funny comment.

CMakeLists.txt Outdated
@@ -104,6 +104,7 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/core
SYSTEM ${additional_includes}
SYSTEM libs/json11
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When #188 gets merged, I guess json11 can become a dependency of the mission plugin only, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, right.

Copy link
Collaborator

@hamishwillee hamishwillee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The new functionality is good.
  2. This does need a unit test.
  3. This replaces the example showing normal use of the API with use of the QGC plan. The implication is that you don't want to show people how to use the API, you only expect them to use the QGC plan.
  • IMO you either show both cases or you have a separate example for the qgc plan import.
  • Personally I would revert to the previous example (but with your excellent documentation header) and either have a standalone example, or possibly just point users to the unit test - that should be enough information.
  1. If this is part of the example code, I'd supply a dummy plan. This will make it easier for users to play with.

@shakthi-prashanth-m
Copy link
Contributor Author

@hamishwillee Thanks for your review comments.

This does need a unit test.

Yes, next commit will have it.

This replaces the example showing normal use of the API with use of the QGC plan. The implication is that you don't want to show people how to use the API, you only expect them to use the QGC plan.
IMO you either show both cases or you have a separate example for the qgc plan import.

Good observation. But we've example usage of it in integration tests. So, we don't need to show it in example.

Personally I would revert to the previous example (but with your excellent documentation header) and either have a standalone example, or possibly just point users to the unit test - that should be enough information.

Thanks. Sure, I would prefer to show Fly mission example with QGC import mission feature as it is user-friendly.

If this is part of the example code, I'd supply a dummy plan. This will make it easier for users to play with.

Plan for example code ? Please share.

@hamishwillee
Copy link
Collaborator

@shakthi-prashanth-m

Good observation. But we've example usage of it in integration tests. So, we don't need to show it in example.

Well you're going to have examples of everything in the integration tests or unit tests, so you might argue why have any examples at all. See below ....

Personally I would revert to the previous example (but with your excellent documentation header) and either have a standalone example, or possibly just point users to the unit test - that should be enough information.

Thanks. Sure, I would prefer to show Fly mission example with QGC import mission feature as it is user-friendly.

Example code should be designed to show off the most commonly used parts of the API or the tricky bits of the API. Essentially I think I can very easily work out how to use the QGC import function by inspection, but using the main API is more challenging.

If you really think that 90% of users will be working off a QGC plan then maybe, but I doubt that is the case.

I don't mind if you have both :-)

Maybe @julianoes can tie break.

If this is part of the example code, I'd supply a dummy plan. This will make it easier for users to play with.

Plan for example code ? Please share.

What I mean is that for this example the instructions would have to say "go create a plan in QGC, download it, then run our example code using this command line ...". I am proposing that you provide a pre-created QGC plan (ie not a "dummy plan", sorry for wording) so that the instructions can be something like "You can test this by using the following command line".

@shakthi-prashanth-m
Copy link
Contributor Author

shakthi-prashanth-m commented Jan 30, 2018

OK, I understand your point @hamishwillee .
I would like to summarize next steps for this PR as below:

  1. Add unit test for import QGC mission feature which tests with a sample QGC plan.

  2. Lets keep the existing Fly mission example as it demonstrates core Mission APIs (improving documentation header).

  3. Add Fly QGC mission example to demonstrate popular QGC plan.

@julianoes @hamishwillee please share your opinion.

Thanks

@shakthi-prashanth-m shakthi-prashanth-m changed the title Add Mission plugin capability to import mission from QGC plan [WIP] Add Mission plugin capability to import mission from QGC plan Jan 30, 2018
@shakthi-prashanth-m shakthi-prashanth-m force-pushed the import-qgc-plan-mission branch 2 times, most recently from bed6160 to db1474f Compare February 4, 2018 03:52
@shakthi-prashanth-m
Copy link
Contributor Author

@julianoes @hamishwillee @JonasVautherin Kindly review. Thanks.

@shakthi-prashanth-m shakthi-prashanth-m changed the title [WIP] Add Mission plugin capability to import mission from QGC plan Add Mission plugin capability to import mission from QGC plan Feb 4, 2018
@shakthi-prashanth-m
Copy link
Contributor Author

[----------] 1 test from QGCMissionImport
[ RUN      ] QGCMissionImport.ValidateQGCMissonItems
[       OK ] QGCMissionImport.ValidateQGCMissonItems (1 ms)
[----------] 1 test from QGCMissionImport (1 ms total)

.gitmodules Outdated
@@ -13,3 +13,6 @@
[submodule "grpc/server/proto"]
path = grpc/server/proto
url = https://github.com/dronecore/DroneCore-Proto.git
[submodule "plugins/mission/libs/json11"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to have it inside the plugin :-).

How about putting it in third_party instead of libs? I started using third_party because that's what they use in gRPC and many of its dependencies (maybe that's a Google convention, Idk), and I find it clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to have it inside the plugin :-)

Yes, I placed it inside mission as it is dependency of the plugin alone.

How about putting it in third_party instead of libs? I started using third_party because that's what they use in gRPC and many of its dependencies (maybe that's a Google convention, Idk), and I find it clearer.

I see. Yeah AFAIK we have a choice: external or third_party. I'm not particular about it, but I see that external is popular. What do you think ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion on this but we should be consistent if possible. If it changes, then let me know because this is used in the docs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like third_party, firstly because there is no possible confusion for me, and also because that's the one I see in grpc, protobuf, boringssl, that are our dependencies already.

@shakthi-prashanth-m
Copy link
Contributor Author

Travis CI says below error while performing Docker build for Ubuntu & Fedora.

This job ran on our Trusty environment,
which has been updated on Tuesday, December 12th, 2017.
Read all about this on our blog and take note that you can
add group: deprecated-2017Q4 in your .travis.yml file to use the previous image version. 

Rest are successful. Can we ignore this ?

@JonasVautherin
Copy link
Collaborator

Travis fails on Ubuntu and Fedora because of a style error (see last lines of the log). Regarding the update warning, IMO it is not so important for us, so we can ignore it.

@shakthi-prashanth-m
Copy link
Contributor Author

@JonasVautherin Yeah, its strange; when I ran this locally, there are no such style errors reported.

@JonasVautherin
Copy link
Collaborator

Does the ./fix_style.sh work locally? Maybe you have to run it manually :-).

@shakthi-prashanth-m
Copy link
Contributor Author

Yes. I ran make fix_style which in-turn invokes fix_style.sh. But none reported.

Copy link
Collaborator

@julianoes julianoes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, looks fairly correct. Does it run as part of the make run_unit_tests?

See various inline comments.

@@ -107,6 +107,7 @@ if(NOT IOS AND NOT ANDROID)
# SYSTEM because we don't want warnings for gtest headers.
include_directories(SYSTEM libs/gtest/googletest/include)
include_directories(SYSTEM libs/gtest/googlemock/include)
include_directories(${CMAKE_SOURCE_DIR}/core)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

@@ -117,7 +118,9 @@ if(NOT IOS AND NOT ANDROID)
timeout_handler_test.cpp
call_every_handler_test.cpp
curl_test.cpp
# FIXME: Below line is NOT capturing plugin unit tests sources. So adding manually.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation, make sure to switch to spaces.

using namespace std::this_thread; // for sleep_for()

// FIXME: Using relative path for QGC mission plan. What's the right way ?
const std::string DEFAULT_QGC_MISSION_PLAN = "../../../plugins/mission/qgroundcontrol_sample.plan";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add a sample in the example folder.

#endif

// Add mission item to the list
mission_items.push_back([&]() -> std::shared_ptr<MissionItem> const {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What bugs me a little bit is that the importer does not combine the mavlink mission items together into dronecore mission items.

So, for the optimal case, a location + speed command + gimbal command would optimally end up in the same dronecore mission item. Basically, all commands following a location should be cominbed with the location.

case MAV_CMD_NAV_WAYPOINT:
is_fly_through = (params[0] == 0.0) ? true : false;
// NO break here, because params 4, 5 & 6 of both
// of these commands are Lat, Lon & Alt respectively.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add // FALLTHROUGH for GCC 7.

@shakthi-prashanth-m
Copy link
Contributor Author

@julianoes Yes, it runs as part of make run_unit_tests

Shakthi Prashanth M and others added 15 commits February 15, 2018 20:02
Previous name is too long and unnecessary. Hence renamed to keep
API name simple and effective.
Rename `Mission::import_QGC_mission()` to
`Mission::import_qgroundcontrol_mission()` to maintain snake_case style.
1. Moved building unit tests to main CMakeLists.txt.
2. Renamed libs to "third_party".
3. Methods used to import mission are renamed for clarity.
4. Enum for AirSpeed, GroundSpeed are explicity intialized for protability.
Move to plugins/mission/third_party/json11
As per https://git-scm.com/docs/gitmodules#_description, "name" is
the name of the submodule. Hence this commit does make sure each
submodule entry abides by it.
Corrected name of submodules: mavlink and dronecore-proto.
This fixes Windows build error.
Its not necessary anymore as it is done in dronecore lib itself.
Moved QGC sample path to plugins/mission and used absolute path
in unit test. Absolute path is composed to work on Windows as well.
For Debug configuration, we need to copy debug versions of DLL.
QGC sample plan is moved to "plugins/mission". Removed "-g" flag
in building Fly QGC example.
CI fails to find debug version of DLLs and hence reverting changes
to copy release versions of DLLs even in debug configuration.
@@ -11,6 +11,13 @@
#include "global_include.h"
#include "log.h"

// To locate QGroundControl plan file during Unit test.
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shakthi-prashanth-m you can just use #ifdef WINDOWS it's what we already have in the build system.

const std::string DEFAULT_QGC_MISSION_PLAN = "../qgroundcontrol_sample.plan";
std::string qgc_plan(DEFAULT_QGC_MISSION_PLAN);
// Locate path of QGC Sample plan
std::string qgc_plan = "../../../plugins/mission/qgroundcontrol_sample.plan";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, I would duplicate the .plan file but for now that's ok.

Used `WINDOWS` macro for consistency.
@shakthi-prashanth-m
Copy link
Contributor Author

@julianoes now ready to be merged unless @hamishwillee requests for changes.

@julianoes julianoes merged commit f7354e3 into develop Feb 15, 2018
@julianoes julianoes deleted the import-qgc-plan-mission branch February 15, 2018 16:09
@julianoes
Copy link
Collaborator

Thanks @shakthi-prashanth-m for the continuous fixing and improvements 😄.

@hamishwillee
Copy link
Collaborator

Congratulations on getting this in @shakthi-prashanth-m ! I'll *try to get associated docs updates in next week: mavlink/MAVSDK-docs#99

@shakthi-prashanth-m
Copy link
Contributor Author

Congratulations on getting this in @shakthi-prashanth-m ! I'll *try to get associated docs updates in next week: mavlink/MAVSDK-docs#99

Thanks @hamishwillee .
I would like to thank @julianoes and @JonasVautherin for the review and valuable suggestions! 👍

dlech pushed a commit to dlech/MAVSDK that referenced this pull request Jan 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants