Skip to content

Commit

Permalink
Add some retry logic to ensure all parameters are fetched in the getP…
Browse files Browse the repository at this point in the history
…aramList method.

Minor corrections to Linux build instructions.
  • Loading branch information
lovettchris committed Mar 23, 2017
1 parent 1f2c5ff commit 26ab718
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 20 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ bld/
[Oo]bj/
Intermediate/
Binaries/
llvm-build/
llvm-source/

# CMake files
CMakeFiles/
Expand Down
78 changes: 75 additions & 3 deletions MavLinkCom/src/impl/MavLinkNodeImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,15 +302,49 @@ std::vector<MavLinkParameter> MavLinkNodeImpl::getParamList()

while (!done) {
waiting = true;
if (!paramReceived.timed_wait(5000))
if (!paramReceived.timed_wait(3000))
{
con->unsubscribe(subscription);
throw std::runtime_error(Utils::stringf("Five second timeout waiting for parameter number %d of %d", paramIndex + 1, paramCount));
// timeout, so we'll drop through to the code below which will try and fix this...
done = true;
}
waiting = false;
}
con->unsubscribe(subscription);

// note that UDP does not guarantee delivery of messages, so we have to also check if some parameters are missing and get them individually.
std::vector<size_t> missing;

for (size_t i = 0; i < paramCount; i++)
{
// nested loop is inefficient, but it is needed because UDP also doesn't guarantee in-order delivery
bool found = false;
for (auto iter = result.begin(), end = result.end(); iter != end; iter++)
{
MavLinkParameter p = *iter;
if (p.index == i) {
found = true;
break;
}
}
if (!found) {
missing.push_back(i);
}
}

// ok, now fetch the missing parameters.
for (auto iter = missing.begin(), end = missing.end(); iter != end; iter++)
{
size_t index = *iter;
MavLinkParameter r;
if (getParameterByIndex(static_cast<int16_t>(*iter)).wait(2000, &r)) {
result.push_back(r);
}
else {
Utils::logMessage("Paremter %d does not seem to exist", index);
}
}


std::sort(result.begin(), result.end(), [&](const MavLinkParameter & p1, const MavLinkParameter & p2) {
return p1.name.compare(p2.name) < 0;
});
Expand Down Expand Up @@ -383,6 +417,44 @@ AsyncResult<MavLinkParameter> MavLinkNodeImpl::getParameter(const std::string& n
return asyncResult;
}

AsyncResult<MavLinkParameter> MavLinkNodeImpl::getParameterByIndex(int16_t index)
{
auto con = ensureConnection();
AsyncResult<MavLinkParameter> asyncResult([=](int state) {
con->unsubscribe(state);
});

MavLinkParamRequestRead cmd;
cmd.param_id[0] = '\0';
cmd.param_index = index;
cmd.target_component = getTargetComponentId();
cmd.target_system = getTargetSystemId();

int subscription = con->subscribe([=](std::shared_ptr<MavLinkConnection> connection, const MavLinkMessage& message) {
if (message.msgid == MavLinkParamValue::kMessageId)
{
MavLinkParamValue param;
param.decode(message);
if (param.param_index == index)
{
MavLinkParameter result;
char buf[17];
std::memset(buf, 0, 17);
std::memcpy(buf, param.param_id, 16);
result.name = buf;
result.type = param.param_type;
result.index = param.param_index;
result.value = UnpackParameter(param.param_type, param.param_value);
asyncResult.setResult(result);
}
}
});
asyncResult.setState(subscription);
sendMessage(cmd);

return asyncResult;
}

AsyncResult<bool> MavLinkNodeImpl::setParameter(MavLinkParameter p)
{
int size = static_cast<int>(p.name.size());
Expand Down
1 change: 1 addition & 0 deletions MavLinkCom/src/impl/MavLinkNodeImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ namespace mavlinkcom_impl {
virtual void handleMessage(std::shared_ptr<MavLinkConnection> connection, const MavLinkMessage& message);
private:
void sendHeartbeat();
AsyncResult<MavLinkParameter> getParameterByIndex(int16_t index);
bool inside_handle_message_;
std::shared_ptr<MavLinkConnection> connection_;
int subscription_ = 0;
Expand Down
25 changes: 25 additions & 0 deletions cmake/getlibcxx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#! /bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"

# add llvm-source to root of AirSim
cd ..

# Checkout LLVM sources
git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm-source
git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm-source/projects/libcxx
git clone --depth=1 https://github.com/llvm-mirror/libcxxabi.git llvm-source/projects/libcxxabi

export C_COMPILER=clang
export COMPILER=clang++

# Build and install libc++
mkdir llvm-build && cd llvm-build
cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr \
../llvm-source
make cxx
sudo make install-cxxabi install-cxx

popd
41 changes: 24 additions & 17 deletions docs/linux_build.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Linux Build

These are the instructions to build AirSim on a Linux machine.
Note: you can also do this from [BashOnWindows](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide)
but make sure you are `not` using a `Visual Studio Command Prompt` because we don't want cmake to accodemtally find VC++ and try and use that.

We need to use `clang compiler` because Unreal engine requires that.

## cmake

First you will need at least [cmake version 3.5](https://cmake.org/install/).
Expand All @@ -17,27 +23,23 @@ sudo apt-get update
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install clang-3.9 clang++-3.9
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.9 60 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-3.9
````

Next you will need the latest version of libc++ library, which you can build yourself by doing this:

If that doesn't work then try this (for Ubuntu 16 only):
````
# Checkout LLVM sources
git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm-source
git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm-source/projects/libcxx
git clone --depth=1 https://github.com/llvm-mirror/libcxxabi.git llvm-source/projects/libcxxabi
export C_COMPILER=clang
export COMPILER=clang++
sudo apt-get update
wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main"
sudo apt-get install clang-3.9 clang++-3.9
````
Now make clang-3.9 your default version of clang with this command:
````
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.9 60 --slave /usr/bin/clang++ clang++ /usr/bin/clang++-3.9
````
Next you will need the latest version of libc++ library, which you can get by running this:

# Build and install libc++
mkdir llvm-build && cd llvm-build
cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} \
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr \
../llvm-source
make cxx -j2
sudo make install-cxxabi install-cxx
````
./cmake/getlibcxx.sh
````

Now you can run the build.sh at the root level of the AirSim repo:
Expand All @@ -50,3 +52,8 @@ This will create a `build_debug` folder containing the build output and the cmak
## Reset build

If for any reason you need to re-run cmake to regenerate new make files just deete the `build_debug` folder.

## Running Unreal on Linux

Now you are ready to follow these instructions to get [Unreal working on Linux](https://wiki.unrealengine.com/Building_On_Linux#Clang) but note that everywhere
you see Clang3.5 in the Unreal documentation replace that with clang3.9.

0 comments on commit 26ab718

Please sign in to comment.