MAVSDK(c++) takeoff_and_land程序分析

MAVSDKc++) takeoff_and_land程序分析

takeoff_and_land程序是用c++语言调用MAVSDK API做起飞和降落的控制。

MAVSDKC++API是对mavlink API的一层抽象,让开发者在用程序语言控制飞机时更简单了。用c语言直接调用mavlink APIPX4操作时你需要用mavlink消息与PX4通讯,需要显式地建立mavlink消息的读/写线程,需要对mavlink消息在传输前后做编码和解码,在使用了MAVSDK API后,这些都省了。然而,在使用MAVSDK时还是要注意两个方面一个是C++的技巧,另一方面是对MAVSDK API的理解。

既然是比mavlink的操作更抽象了,可以理解,新的API和语言也更抽象了。抽象的方法是不亮出操作的对象具体是什么,你也不能直接建立这个对象,但是你可以用操作这个对象的函数来操作它,包括得到它、改变它并传递它。

对于get_system()这个函数,我们做分析:

get_system()函数原型是std::shared_ptr<System> get_system(Mavsdk& mavsdk)

表示:这个函数将返回指向System对象的指针。

其中,shared_ptr它的原型是std::shared_ptr<类型>shared_ptr类型是一个c++标准库中的一种smart指针,是一个类模板。当shared_ptr指向的对象生命周期结束时(比如:离开控制块作用的范围),会自动调用其析构函数,释放内存。而不再需要程序员显式地调用delete释放对象。

auto prom = std::promise<std::shared_ptr<System>>{};

表示用指向System对象的指针对promise类进行初始化,并赋值给prom变量,其中指向System对象的指针是shared_ptr类型,prom保存了一个promise类的实例。

C++11中,auto表示,对于声明的变量,编译器可以根据变量初始值的类型自动为此变量选择匹配的类型。

prom是一个promise对象的实例,它保存了一个指向System对象的指针

auto fut = prom.get_future();

表示:利用prom.get_future()得到一个future对象,这样promfut就关联起来了,futprom有了一个共享的状态,并且fut可以从prom中获取指向System的指针。

C++中,promisefuture对象是成对出现的。一个线程拥有prom,另外一个线程拥有fut,两个线程就可以通过promfut这两个对象交换数据。这样,利用promisefuture机制就把两个线程之间交换数据变成了两个对象之间交换数据。尤其面向这样一种情况,拥有prom的那个线程不是马上就可以得到结果,而是要过一段不确定的时间才能得到结果,在结果得到后,等待它出现结果的线程需要与这个产生结果的线程有一个同步的操作,在promisefuture这两个对象引入后,虽然你看不见这个同步的具体操作,但是你可以在promfut这两个对象共享的状态上进行操作,比如查看状态的变化。事实上,两个异步线程之间交换数据并不是一件容易的事,尤其是一个线程还要与另一个线程在某个时刻同步。采用promise/future技术简化了这个过程。

本例中,prommavsdk.subscribe_on_new_system拥有,fut被主线程拥有。

mavsdk.subscribe_on_new_system原型:

void mavsdk::Mavsdk::subscribe_on_new_system(NewSystemCallback callback)

对这个函数的解释:

systems一旦发生变化这个程序将得到通知。(原文:Get notification about a change in systems

一旦有一个新的system加入进来就调用这个函数 。(原文:This gets called whenever a system is added

上述说明中的‘systems’是指可以从mavsdk的成员函数systems()得到的一个向量。原型:

std::vector<std::shared_ptr<System> > mavsdk::Mavsdk::systems() const

其中SystemMAVSDK中定义的一个类,代表了一个系统,由一个或多个部件组成(自驾仪,照相机,云台,舵机...)。也就是说在MAVSDK系统中存在一个向量:system1, system2 ….这里system对象不能直接由应用程序建立,想得到它,要通过调用MAVSDK API对它进行操作。比如:想得到这个向量的最后一个成员 auto system = mavsdk.system().back();

本例是直接把回调函数体作为参数传给subscribe_on_new_system虽然你看不出mavsdk.subscribe_on_new_system是一个线程,但是你应该想象它启动了一个线程,这个线程在通讯接口上等待接收heatbeat消息。

mavsdk系统(server)在发现了一个新的System后会通知mavsdk.subscribe_on_new_system执行回调函数。回调函数体如下:

callback[&mavsdk, &prom]() {

// 获取刚刚获得的system

auto system = mavsdk.systems().back();

// 判断这个system有没有autopilot部件

if (system->has_autopilot()) {

std::cout << "Discovered autopilot\n";

// Unsubscribe again as we only want to find one system.

// 不再接收其他发现的系统

mavsdk.subscribe_on_new_system(nullptr);

// fut做同步,将future_status的状态改为ready

// system传给fut

prom.set_value(system);

}

});

// 主线成阻塞在这里,等待future_status状态改变

// 如果在等待的3秒之内发现状态是timeout,则返回空值。

if (fut.wait_for(seconds(3)) == std::future_status::timeout) {

std::cerr << "No autopilot found.\n";

return {};

}

// 如果在等待的3秒之内发现不是timeout,则返回发现的system

return fut.get();

当然如果一个线程不是等待一段不确定的时间才拿到结果,我们就不需要用promise/future技术,因为future是确定的。比如:想从数传中得到高度信息,MAVSDK给出的APItelemetry.subscribe_position,片段如下:

//先申请一个telemetry对象

auto telemetry = Telemetry{system};

//然后确定监测飞机position消息的频率1Hz

const auto set_rate_result = telemetry.set_rate_position(1.0);

//最后,查看并打印position中的altitude_m分量(高度)

telemetry.subscribe_position([](Telemetry::Position position) {

std::cout << "Altitude: " << position.relative_altitude_m << " m\n";

});

可以想象telemetry_subscribe_postion也是启动了一个线程,它从飞机定期得到位置消息11Hz就会启动一次回调函数,回调函数做打印操作。由于是确定性事件,所以没有必要用promise/future技术。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值