日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Pixhawk之姿态解算篇(3)_源码姿态解算算法分析

發(fā)布時(shí)間:2024/4/18 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Pixhawk之姿态解算篇(3)_源码姿态解算算法分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、開篇

? ? ? ? 終于到ardupilot源代碼的姿態(tài)解算了,有了前期關(guān)于mahony姿態(tài)解算算法的基礎(chǔ)以后,理解源代碼的姿態(tài)解算算法就快多了,所有的東西都在腦海中初步有了一個(gè)框架;首先要做什么,然后再做什么,再然后捏~~~反正容易上手的。

? ? ? ? 2016.04.04日晚,別人都在嗨,而我卻在實(shí)驗(yàn)室苦逼的工作著,今晚最大的收獲就是發(fā)現(xiàn)了“新大陸”-----“北航可靠飛行控制研究組”,其喜悅之情絕不亞于哥倫布發(fā)現(xiàn)新大陸。他們才是專業(yè)的啊,看看他們畢業(yè)生的去向,不是研究所就是出國深造,好吧,人家才是專業(yè)搞科研的,不食人間煙火,那么問題來了:DJI的員工都是在哪招來的呢?!哎,我是俗人一個(gè),經(jīng)濟(jì)基礎(chǔ)決定上層建筑,好好學(xué)習(xí)才能掙大錢。最近他們開設(shè)了一門課程《多旋翼飛行器設(shè)計(jì)與控制》,課程體系安排的非常好,現(xiàn)在更新到第四講了(聽北航一個(gè)博士說只有PPT沒有視頻,感謝Mallin的幫助,成功打入內(nèi)部),PPT也足夠了,相當(dāng)上檔次啊,課程到2016.06.30結(jié)束,正好可以把無人機(jī)的整個(gè)架構(gòu)理解完,找工作去~~~

? ? ? ? 在下面的基礎(chǔ)知識(shí)部分先分享一部分“北航”的研究成果,特別是氣動(dòng)方面的,以前一點(diǎn)概念都沒有,只看著超跑的流線型非常炫酷,不知其原因,特此記錄,大家共勉。


三、實(shí)驗(yàn)平臺(tái)

Software?Version:PX4Firmware

Hardware Version:pixhawk

IDE:eclipse Juno (Windows)

四、基礎(chǔ)知識(shí)(均來自北航可靠飛行控制研究組)

1、無人機(jī)飛行的氣動(dòng)模型與分析

? ? ? ? 1)多旋翼前飛情形:在下圖中,因?yàn)槁菪龢娜嵝?#xff0c;誘導(dǎo)的來流會(huì)產(chǎn)生阻力。

? ? ? ? 如果多旋翼重心在槳盤平面下方,那么阻力形成的力矩會(huì)促使多旋翼俯仰角轉(zhuǎn)向0度方向。

? ? ? ? 如果多旋翼重心在槳盤平面上方,那么阻力形成的力矩會(huì)促使多旋翼俯仰角朝發(fā)散方向發(fā)展,直至翻轉(zhuǎn)。因此,當(dāng)多旋翼前飛時(shí),重心在槳盤平面的下方會(huì)使前飛運(yùn)動(dòng)穩(wěn)定。

? ? ? ? 2)多旋翼風(fēng)干擾情形:在下圖中,當(dāng)陣風(fēng)吹來,因?yàn)槁菪龢娜嵝?#xff0c;誘導(dǎo)的來流會(huì)在產(chǎn)生阻力。

? ? ? ? 如果多旋翼重心在下,那么阻力形成的力矩會(huì)促使多旋翼俯仰角朝發(fā)散的方向發(fā)展,直至翻轉(zhuǎn)。

? ? ? ? 如果多旋翼重心在上,那么阻力形成的力矩會(huì)促使多旋翼俯仰超0度方向發(fā)展。因此,當(dāng)多旋翼受到外界風(fēng)干擾時(shí),重心在槳盤平面的上方可以抑制擾動(dòng)。

? ? ? ? 3)綜上所述:無論重心在槳盤平面的上方或下方都不能使多旋翼穩(wěn)定。因此需要通過反饋控制將多旋翼平衡。然而,如果重心在槳盤平面很靠上的位置,會(huì)使多旋翼某個(gè)運(yùn)動(dòng)模態(tài)很不穩(wěn)定。因此,實(shí)際中建議將重心配置在飛行器槳盤周圍,可以稍微靠下。這樣控制器控制起來更容易些。

2、氣動(dòng)布局

? ? ? ? 對(duì)外形進(jìn)行設(shè)計(jì)主要是為了降低飛行時(shí)的阻力。按其產(chǎn)生的原因不同可分為

(1)摩擦阻力

(2)壓差阻力

(3)誘導(dǎo)阻力

(4)干擾阻力

? ? ? ? 要減少這些阻力,需要妥善考慮和安排各部件之間的相對(duì)位置關(guān)系,部件連接處盡量圓滑過渡,減少漩渦產(chǎn)生。

? ? ? ? 因此它與物體的迎風(fēng)面積有很大關(guān)系,迎風(fēng)面積越大,壓差阻力也越大。物體的形狀也對(duì)壓差阻力影響很大。如上圖所示的三個(gè)物體,圓盤的壓差阻力最大,球體次之,而流線體的最小,就壓差阻力而言可以是平板壓差阻力的1/20。

? ? ? ? 設(shè)計(jì)建議:(法拉利、保馳捷等超跑的流線型車就是很好的榜樣,寶馬 Z4也可以,奔馳Smart就太low了,差點(diǎn)忘記特斯拉了)

(1)需要考慮多旋翼前飛時(shí)的傾角,減少最大迎風(fēng)面積。

(2)并設(shè)計(jì)流線型機(jī)身。

(3)考慮和安排各部件之間的相對(duì)位置關(guān)系,部件連接處盡量圓滑過渡,飛機(jī)表面也要盡量光滑。

(4)通過CFD仿真(Computational Fluid Dynamics:計(jì)算流體動(dòng)力學(xué))計(jì)算阻力系數(shù),不斷優(yōu)化。

? ? ? ? 昨天見到了零度的四旋翼,外形設(shè)計(jì)的就是好,可惜只靠外形還是干不過DJI的,加油吧,零度。

五、正文(源代碼的姿態(tài)解算算法)

1、進(jìn)程入口:voidAttitudeEstimatorQ::task_main()

? ? ? ? 1)訂閱所需要的topics,注意sensor_combined,傳感器數(shù)據(jù)都是靠它來的。

? ? ? ? 在訂閱時(shí)使用ORB_ID(sensor_combined)獲取ID號(hào),該ID號(hào)代表了從topic_name到topicmetadata structure name之間的轉(zhuǎn)換橋梁。在task_main()的初始部分使用uORB模型的orb_subscribe()函數(shù)獲取在sensors.cpp中通過orb_advertise()函數(shù)廣播的傳感器信息(sensor_combined)。由此說明在使用之前需要通過orb_advertise()函數(shù)之后才能在需要其數(shù)據(jù)的地方使用orb_subscribe()獲取。如果沒有使用,訂閱者可以訂閱,但是接收不到有效數(shù)據(jù)。

? ? ? ? 關(guān)于uOBR模型的不再贅述,詳細(xì)介紹參看:http://blog.csdn.net/freeape/article/details/46880637

和http://www.pixhawk.com/start?id=zh%2Fdev%2Fshared_object_communication&go

? ? ? ? px4_poll(fds,1, 1000):配置阻塞時(shí)間,1ms讀取一次sensor_combined的數(shù)據(jù)。

? ? ? ? 必須有了orb_advertise()函數(shù)和orb_subscribe()函數(shù)(通過它獲取orb_copy()函數(shù)中的參數(shù)handle)之后才可以使用orb_copy(ORB_ID(sensor_combined),_sensors_sub, &sensors)函數(shù)獲取sensors的實(shí)際有效數(shù)據(jù)。

? ? ? ? 首先是讀取gyro的數(shù)據(jù):(有個(gè)特別的地方就是把陀螺儀的值先積分然后再微分,這個(gè)其實(shí)就是求平均_2016.05.27補(bǔ)充

[plain] view plain copy
  • float?gyro[3];??
  • for?(unsigned?j?=?0;?j?<?3;?j++)???
  • {??
  • ????if?(sensors.gyro_integral_dt[i]?>?0)??
  • ????{??
  • ????????gyro[j]?=?(double)sensors.gyro_integral_rad[i?*?3?+?j]?/?(sensors.gyro_integral_dt[i]?/?1e6);??
  • }??
  • ?else{??
  • ????????/*?fall?back?to?angular?rate?*/??
  • ????????gyro[j]?=?sensors.gyro_rad_s[i?*?3?+?j];??
  • ????????}??
  • }??
  • ? ? ? ? 然后以同樣的方法讀取accel和mag的數(shù)據(jù)。

    [plain] view plain copy
  • Void?DataValidatorGroup::put(unsigned?index,?uint64_t?timestamp,?float?val[3],?uint64_t?error_count,?int?priority)??
  • {??
  • ????????DataValidator?*next?=?_first;??
  • ????????unsigned?i?=?0;??
  • ????????while?(next?!=?nullptr)?{??
  • ????????????if?(i?==?index)?{??
  • ????????????????next->put(timestamp,?val,?error_count,?priority);//goto??
  • ????????????????break;??
  • ????????????????}??
  • ????????????next?=?next->sibling();//下一組數(shù)據(jù)??
  • ????????????i++;??
  • ????????????}??
  • }??
  • ? ? ? ? 最終還是goto到put函數(shù)。

    [plain] view plain copy
  • Void?DataValidator::put(uint64_t?timestamp,?float?val[3],?uint64_t?error_count_in,?int?priority_in)??
  • {??
  • ????_event_count++;??
  • ????if?(error_count_in?>?_error_count)?{??
  • ????????_error_density?+=?(error_count_in?-?_error_count);??
  • ????}?else?if?(_error_density?>?0)?{??
  • ????????_error_density--;??
  • ????}??
  • ????_error_count?=?error_count_in;??
  • ????_priority?=?priority_in;??
  • ????for?(unsigned?i?=?0;?i?<?_dimensions;?i++)?{//_dimensions=3??
  • ????????if?(_time_last?==?0)?{//時(shí)間變量已經(jīng)初始化為0??
  • ????????????_mean[i]?=?0;??
  • ????????????_lp[i]?=?val[i];??
  • ????????????_M2[i]?=?0;??
  • ????????}?else?{??
  • ????????????float?lp_val?=?val[i]?-?_lp[i];??
  • ????????????float?delta_val?=?lp_val?-?_mean[i];??
  • ????????????_mean[i]?+=?delta_val?/?_event_count;??
  • ????????????_M2[i]?+=?delta_val?*?(lp_val?-?_mean[i]);??
  • ????????????_rms[i]?=?sqrtf(_M2[i]?/?(_event_count?-?1));??
  • ????????????if?(fabsf(_value[i]?-?val[i])?<?0.000001f)?{??
  • ????????????????_value_equal_count++;??
  • ????????????}?else?{??
  • ????????????????_value_equal_count?=?0;??
  • ????????????}??
  • ????????}??
  • ????????//?XXX?replace?with?better?filter,?make?it?auto-tune?to?update?rate??
  • ????????_lp[i]?=?_lp[i]?*?0.5f?+?val[i]?*?0.5f;??
  • ????????_value[i]?=?val[i];??
  • ????}??
  • ????_time_last?=?timestamp;??
  • }??
  • ? ? ? ? 詳細(xì)介紹使用方法:主要是將三類參數(shù)分別建立相應(yīng)的 DataValidatorGroup類來對(duì)數(shù)據(jù)進(jìn)行處理。

    ? ? ? ? DataValidatorGroup類: _voter_gyro、_voter_accel、_voter_mag

    ???????? 調(diào)用方法:

    ???????? 1)首先gyro、accel、mag每次讀取數(shù)據(jù)都是三組三組的讀取

    ???????? 2)先將每組的數(shù)據(jù)(例如gyro將三個(gè)維度的的傳感器數(shù)據(jù)put入(如_voter_gyro.put(...)))DataValidatorGroup中,并goto到DataValidator::put函數(shù)

    ???????? 3)在DataValidator函數(shù)中計(jì)算數(shù)據(jù)的誤差、平均值、并進(jìn)行濾波。

    ??? 濾波入口的put函數(shù):

    ???????? val=傳感器讀取的數(shù)據(jù)

    ???????? _lp=濾波器的系數(shù)(lowpass value)

    ???????? 初始化:由上圖可知當(dāng)?shù)谝淮巫x到傳感器數(shù)據(jù)時(shí)_mean和_M2置0,_lp=val;

    ???????? lp_val= val - _lp

    ???????? delta_val= lp_val - _mean

    ???????? _mean= (平均值)每次數(shù)據(jù)讀取時(shí),每次val和_lp的差值之和的平均值 _mean[i] += delta_val / _event_count

    ???????? _M2= (均方根值)delta_val * (lp_val - _mean)的和

    ???????? _rms= 均方根值sqrtf(_M2[i] / (_event_count - 1))

    ???????? 優(yōu)化濾波器系數(shù):_lp[i]= _lp[i] * 0.5f + val[i] * 0.5f

    ???????? _value= val :get_best()函數(shù)的最后調(diào)用該結(jié)果(通過比較三組數(shù)據(jù)的confidence大小決定是否選取)。

    ??? 濾波器的confidence函數(shù)(信任度函數(shù),貌似模糊控制理論有個(gè)隸屬函數(shù),應(yīng)該類似的功能):返回值是對(duì)上N次測(cè)量的驗(yàn)證的信任程度,其值在0到1之間,越大越好。返回值是返回上N次測(cè)量的誤差診斷,用于get_best函數(shù)選擇最優(yōu)值,選擇的方法如下:

    ?Switch if:

    ???????? 1)the confidence is higher and priority is equal or higher

    ???????? 2)the confidence is no less than 1% different and the priority is higher

    2、根據(jù)_voter_gyro、_voter_accel、_voter_mag三個(gè)參數(shù)的failover_count函數(shù)判斷是否存在數(shù)據(jù)獲取失誤問題,并通過mavlink協(xié)議顯示錯(cuò)誤原因。

    3、根據(jù)_voter_gyro、_voter_accel、_voter_mag三個(gè)參數(shù)的get_vibration_factor函數(shù)判斷是否有震動(dòng)現(xiàn)象,返回值是float型的RSM值,其代表振動(dòng)的幅度大小。

    [plain] view plain copy
  • Float?DataValidatorGroup::get_vibration_factor(uint64_t?timestamp)??
  • {??
  • ????DataValidator?*next?=?_first;??
  • ????float?vibe?=?0.0f;??
  • ????/*?find?the?best?RMS?value?of?a?non-timed?out?sensor?*/??
  • ????while?(next?!=?nullptr)?{??
  • ????????if?(next->confidence(timestamp)?>?0.5f)?{??
  • ????????????float*?rms?=?next->rms();??
  • ????????????for?(unsigned?j?=?0;?j?<?3;?j++)?{??
  • ????????????????if?(rms[j]?>?vibe)?{??
  • ????????????????????vibe?=?rms[j];//獲取最大值??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????next?=?next->sibling();??
  • ????}??
  • ????return?vibe;//返回DataValidatorGroup中的三組中的最大的振動(dòng)值??
  • }??
  • ? ? ? ? 將rms變量(原來put函數(shù)中的_rms)傳回主函數(shù)中和_vibration_warning_threshold進(jìn)行判斷。

    4、通過uORB模型獲取vision和mocap的數(shù)據(jù)(視覺和mocap)

    [plain] view plain copy
  • //?Update?vision?and?motion?capture?heading??
  • ????????bool?vision_updated?=?false;??
  • ????????orb_check(_vision_sub,?&vision_updated);??
  • ????????bool?mocap_updated?=?false;??
  • ????????orb_check(_mocap_sub,?&mocap_updated);??
  • ????????if?(vision_updated)?{??
  • ????????????orb_copy(ORB_ID(vision_position_estimate),?_vision_sub,?&_vision);??
  • ????????????math::Quaternion?q(_vision.q);??
  • ????????????math::Matrix<3,?3>?Rvis?=?q.to_dcm();??
  • ????????????math::Vector<3>?v(1.0f,?0.0f,?0.4f);??
  • ????????????//?Rvis?is?Rwr?(robot?respect?to?world)?while?v?is?respect?to?world.??
  • ????????????//?Hence?Rvis?must?be?transposed?having?(Rwr)'?*?Vw??
  • ????????????//?Rrw?*?Vw?=?vn.?This?way?we?have?consistency??
  • ????????????_vision_hdg?=?Rvis.transposed()?*?v;??
  • ????????}??
  • ????????if?(mocap_updated)?{??
  • ????????????orb_copy(ORB_ID(att_pos_mocap),?_mocap_sub,?&_mocap);??
  • ????????????math::Quaternion?q(_mocap.q);??
  • ????????????math::Matrix<3,?3>?Rmoc?=?q.to_dcm();??
  • ????????????math::Vector<3>?v(1.0f,?0.0f,?0.4f);??
  • ????????????//?Rmoc?is?Rwr?(robot?respect?to?world)?while?v?is?respect?to?world.??
  • ????????????//?Hence?Rmoc?must?be?transposed?having?(Rwr)'?*?Vw??
  • ????????????//?Rrw?*?Vw?=?vn.?This?way?we?have?consistency??
  • ????????????_mocap_hdg?=?Rmoc.transposed()?*?v;??
  • ????????}</span><span?style="font-size:14px;">??
  • 5、位置加速度獲取(position,注意最后在修正時(shí)會(huì)用到該處的_pos_acc)(484)

    ? ? ? ? 首先檢測(cè)是否配置了自動(dòng)磁偏角獲取,如果配置了則用當(dāng)前的經(jīng)緯度(longitude and latitude)通過get_mag_declination(_gpos.lat,_gpos.lon)函數(shù)獲取當(dāng)前位置的磁偏角(magnetic declination),實(shí)現(xiàn)過程就是一系列的算算算,自己跟蹤源碼看吧,用地面站校準(zhǔn)羅盤的應(yīng)該比較熟悉這個(gè)。然后就是獲取機(jī)體的速度,通過速度計(jì)算機(jī)體的加速度。

    [plain] view plain copy
  • bool?gpos_updated;??
  • ????????orb_check(_global_pos_sub,?&gpos_updated);??
  • ????????if?(gpos_updated)?{??
  • ????????????orb_copy(ORB_ID(vehicle_global_position),?_global_pos_sub,?&_gpos);??
  • ????????if?(_mag_decl_auto?&&?_gpos.eph?<?20.0f?&&?hrt_elapsed_time(&_gpos.timestamp)?<?1000000)?{??
  • ????????????????/*?set?magnetic?declination?automatically?*/??
  • ????????????????_mag_decl?=?math::radians(get_mag_declination(_gpos.lat,?_gpos.lon));??
  • ????????????}??
  • ????????}??
  • ????????if?(_acc_comp?&&?_gpos.timestamp?!=?0?&&?hrt_absolute_time()?<?_gpos.timestamp?+?20000?&&?_gpos.eph?<?5.0f?&&?_inited)?{??
  • ????????????/*?position?data?is?actual?*/??
  • ????????????if?(gpos_updated)?{??
  • ????????????????Vector<3>?vel(_gpos.vel_n,?_gpos.vel_e,?_gpos.vel_d);??
  • ????????????????/*?velocity?updated?*/??
  • ????????????????if?(_vel_prev_t?!=?0?&&?_gpos.timestamp?!=?_vel_prev_t)?{??
  • ????????????????????float?vel_dt?=?(_gpos.timestamp?-?_vel_prev_t)?/?1000000.0f;??
  • ????????????????????/*?calculate?acceleration?in?body?frame?:速度之差除時(shí)間*/??
  • ????????????????????_pos_acc?=?_q.conjugate_inversed((vel?-?_vel_prev)?/?vel_dt);??
  • ????????????????}??
  • ????????????????_vel_prev_t?=?_gpos.timestamp;??
  • ????????????????_vel_prev?=?vel;??
  • ????????????}??
  • ????????}?else?{??
  • ????????????/*?position?data?is?outdated,?reset?acceleration?*/??
  • ????????????_pos_acc.zero();??
  • ????????????_vel_prev.zero();??
  • ????????????_vel_prev_t?=?0;??
  • ????????}??
  • 6、update函數(shù)(528行)

    ? ? ? ? 接下來就是528行的updata函數(shù)了,非常重要,這個(gè)函數(shù)主要用于對(duì)四元數(shù)向量_q進(jìn)行初始化賦值或者更新。

    ? ? ? ? --------------------------------------------------------------------------------------------------------------------------

    ? ? ? ? 首先判斷是否是第一次進(jìn)入該函數(shù),第一次進(jìn)入該函數(shù)先進(jìn)入init函數(shù)初始化,源碼如下。

    [plain] view plain copy
  • bool?AttitudeEstimatorQ::init()??
  • {??
  • ????//?Rotation?matrix?can?be?easily?constructed?from?acceleration?and?mag?field?vectors??
  • ????//?'k'?is?Earth?Z?axis?(Down)?unit?vector?in?body?frame??
  • ????Vector<3>?k?=?-_accel;??
  • ????k.normalize();??
  • ????//?'i'?is?Earth?X?axis?(North)?unit?vector?in?body?frame,?orthogonal?with?'k'??
  • ????Vector<3>?i?=?(_mag?-?k?*?(_mag?*?k));??
  • ????i.normalize();??
  • ????//?'j'?is?Earth?Y?axis?(East)?unit?vector?in?body?frame,?orthogonal?with?'k'?and?'i'??
  • ????Vector<3>?j?=?k?%?i;??
  • ????//?Fill?rotation?matrix??
  • ????Matrix<3,?3>?R;??
  • ????R.set_row(0,?i);??
  • ????R.set_row(1,?j);??
  • ????R.set_row(2,?k);??
  • ????//?Convert?to?quaternion??
  • ????_q.from_dcm(R);??
  • ????_q.normalize();??
  • ????if?(PX4_ISFINITE(_q(0))?&&?PX4_ISFINITE(_q(1))?&&??
  • ????????PX4_ISFINITE(_q(2))?&&?PX4_ISFINITE(_q(3))?&&??
  • ????????_q.length()?>?0.95f?&&?_q.length()?<?1.05f)?{??
  • ????????_inited?=?true;??
  • ????}?else?{??
  • ????????_inited?=?false;??
  • ????}??
  • ????return?_inited;??
  • }??
  • ? ? ? ? 初始化方法:

    ? ? ? ? k= -_accel 然后歸一化k,k為加速度傳感器測(cè)量到加速度方向向量,由于第一次測(cè)量數(shù)據(jù)時(shí)無人機(jī)一般為平穩(wěn)狀態(tài)無運(yùn)動(dòng)狀態(tài),所以可以直接將測(cè)到的加速度視為重力加速度g,以此作為dcm旋轉(zhuǎn)矩陣的第三行k(這個(gè)介紹過了)。

    ? ? ? ? i= (_mag - k * (_mag * k)) _mag向量指向正北方,k*(_mag*k) 正交correction值,對(duì)于最終的四元數(shù)歸一化以后的范數(shù)可以在正負(fù)5%以內(nèi);感覺不如《DCM IMU:Theory》中提出的理論強(qiáng)制正交化修正的好,Renormalization算法在ardupilot的上層應(yīng)用AP_AHRS_DCM中使用到了。

    ? ? ? ? j= k%i :外積、叉乘。關(guān)于上面的Vector<3>k = -_accel,Vector<3>相當(dāng)于一個(gè)類型(int)定義一個(gè)變量k,然后把-_accel負(fù)值給k,在定義_accel時(shí)也是使用Vector<3>,屬于同一種類型的,主要就是為了考慮其實(shí)例化過程(類似函數(shù)重載)。

    ? ? ? ? 然后以模板的形式使用“Matrix<3, 3> R”建立3x3矩陣R,通過set_row()函數(shù)賦值。

    [plain] view plain copy
  • /**??
  • ?*?set?row?from?vector??
  • ?*/??
  • void?set_row(unsigned?int?row,?const?Vector<N>?v)?{??
  • ????for?(unsigned?i?=?0;?i?<?N;?i++)?{??
  • ????????data[row][i]?=?v.data[i];??
  • ????}??
  • }??
  • ? ? ? ? 第一行賦值i 向量指向北,第二行賦值j 向量指向東,第三行賦值k向量指向DOWN。然后就是把DCM轉(zhuǎn)換為四元數(shù)_q (使用from_dcm),并歸一化四元數(shù),一定要保持歸一化的思想。來一個(gè)比較牛掰的求范數(shù)的倒數(shù)的快速算法(mahony的算法實(shí)現(xiàn)用到的):

    [plain] view plain copy
  • float?invSqrt(float?x)?{??
  • ????float?halfx?=?0.5f?*?x;??
  • ????float?y?=?x;??
  • ????long?i?=?*(long*)&y;??
  • ????i?=?0x5f3759df?-?(i>>1);??
  • ????y?=?*(float*)&i;??
  • ????y?=?y?*?(1.5f?-?(halfx?*?y?*?y));??
  • ????return?y;??
  • }??
  • ? ? ? ? 具體為什么這么實(shí)現(xiàn)的還是看wiki連接吧:https://en.wikipedia.org/wiki/Fast_inverse_square_root

    ? ? ? ? 其中DCM轉(zhuǎn)四元數(shù)的算法如下,tr>0時(shí)比較好理解,別的情況被簡寫的看不透了。后續(xù)給出原始代碼便于理解。

    [plain] view plain copy
  • tr?=?dcm.data[0][0]?+?dcm.data[1][1]?+?dcm.data[2][2]??
  • ????如果?tr>0??
  • float?s?=?sqrtf(tr?+?1.0f);??
  • data[0]?=?s?*?0.5f;??
  • s?=?0.5f?/?s;??
  • data[1]?=?(dcm.data[2][1]?-?dcm.data[1][2])?*?s;??
  • data[2]?=?(dcm.data[0][2]?-?dcm.data[2][0])?*?s;??
  • data[3]?=?(dcm.data[1][0]?-?dcm.data[0][1])?*?s;??
  • ? ? ? ? 其他情況去看代碼吧,不好解釋。然后_q 單位化結(jié)束初始化。PS:另外根據(jù)DCM求取四元數(shù)的算法是參考MartinJohn Baker的,就是上述的原始版,該算法在AP_Math/quaternion.cpp中,鏈接:

    http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm

    ? ? ? ? 源碼如下。

    [plain] view plain copy
  • void?Quaternion::from_rotation_matrix(const?Matrix3f?&m)??
  • {??
  • ????const?float?&m00?=?m.a.x;??
  • ????const?float?&m11?=?m.b.y;??
  • ????const?float?&m22?=?m.c.z;??
  • ????const?float?&m10?=?m.b.x;??
  • ????const?float?&m01?=?m.a.y;??
  • ????const?float?&m20?=?m.c.x;??
  • ????const?float?&m02?=?m.a.z;??
  • ????const?float?&m21?=?m.c.y;??
  • ????const?float?&m12?=?m.b.z;??
  • ????float?&qw?=?q1;??
  • ????float?&qx?=?q2;??
  • ????float?&qy?=?q3;??
  • ????float?&qz?=?q4;??
  • ????float?tr?=?m00?+?m11?+?m22;??
  • ????if?(tr?>?0)?{??
  • ????????float?S?=?sqrtf(tr+1)?*?2;??
  • ????????qw?=?0.25f?*?S;??
  • ????????qx?=?(m21?-?m12)?/?S;??
  • ????????qy?=?(m02?-?m20)?/?S;???
  • ????????qz?=?(m10?-?m01)?/?S;???
  • ????}?else?if?((m00?>?m11)?&&?(m00?>?m22))?{???
  • ????????float?S?=?sqrtf(1.0f?+?m00?-?m11?-?m22)?*?2;??
  • ????????qw?=?(m21?-?m12)?/?S;??
  • ????????qx?=?0.25f?*?S;??
  • ????????qy?=?(m01?+?m10)?/?S;???
  • ????????qz?=?(m02?+?m20)?/?S;???
  • ????}?else?if?(m11?>?m22)?{???
  • ????????float?S?=?sqrtf(1.0f?+?m11?-?m00?-?m22)?*?2;??
  • ????????qw?=?(m02?-?m20)?/?S;??
  • ????????qx?=?(m01?+?m10)?/?S;???
  • ????????qy?=?0.25f?*?S;??
  • ????????qz?=?(m12?+?m21)?/?S;???
  • ????}?else?{???
  • ????????float?S?=?sqrtf(1.0f?+?m22?-?m00?-?m11)?*?2;??
  • ????????qw?=?(m10?-?m01)?/?S;??
  • ????????qx?=?(m02?+?m20)?/?S;??
  • ????????qy?=?(m12?+?m21)?/?S;??
  • ????????qz?=?0.25f?*?S;??
  • ????}??
  • }??
  • ? ? ? ? ---------------------------------------------------------------------------------------------------------------------------------? ? ? ? ??

    ? ? ? ? 如果不是第一次進(jìn)入該函數(shù),則判斷是使用什么mode做修正的,比如vision、mocap、acc和mag(DJI精靈4用的視覺壁障應(yīng)該就是這個(gè)vision),Hdg就是heading。

    [plain] view plain copy
  • if?(_ext_hdg_mode?>?0?&&?_ext_hdg_good)?{??
  • ????????if?(_ext_hdg_mode?==?1)?{??
  • ????????????//?Vision?heading?correction??
  • ????????????//?Project?heading?to?global?frame?and?extract?XY?component??
  • ????????????Vector<3>?vision_hdg_earth?=?_q.conjugate(_vision_hdg);??
  • ????????????float?vision_hdg_err?=?_wrap_pi(atan2f(vision_hdg_earth(1),?vision_hdg_earth(0)));??
  • ????????????//?Project?correction?to?body?frame??
  • ????????????corr?+=?_q.conjugate_inversed(Vector<3>(0.0f,?0.0f,?-vision_hdg_err))?*?_w_ext_hdg;??
  • ????????}??
  • ????????if?(_ext_hdg_mode?==?2)?{??
  • ????????????//?Mocap?heading?correction??
  • ????????????//?Project?heading?to?global?frame?and?extract?XY?component??
  • ????????????Vector<3>?mocap_hdg_earth?=?_q.conjugate(_mocap_hdg);??
  • ????????????float?mocap_hdg_err?=?_wrap_pi(atan2f(mocap_hdg_earth(1),?mocap_hdg_earth(0)));??
  • ????????????//?Project?correction?to?body?frame??
  • ????????????corr?+=?_q.conjugate_inversed(Vector<3>(0.0f,?0.0f,?-mocap_hdg_err))?*?_w_ext_hdg;??
  • ????????}??
  • ????}??
  • ? ? ? ? _ext_hdg_mode== 1、2時(shí)都是利用vision數(shù)據(jù)和mocap數(shù)據(jù)對(duì)gyro數(shù)據(jù)進(jìn)行修正,下面的global frame就是所謂的earthframe。

    ? ? ? ? ?---------------------------------------------------------------------------------------------------------------------------------

    ? ? ? ? _ext_hdg_mode== 0利用磁力計(jì)修正。

    [plain] view plain copy
  • if?(_ext_hdg_mode?==?0??||?!_ext_hdg_good)?{??
  • ????????//?Magnetometer?correction??
  • ????????//?Project?mag?field?vector?to?global?frame?and?extract?XY?component??
  • ????????Vector<3>?mag_earth?=?_q.conjugate(_mag);?//b系到n系??
  • ????????float?mag_err?=?_wrap_pi(atan2f(mag_earth(1),?mag_earth(0))?-?_mag_decl);??
  • ????????//?Project?magnetometer?correction?to?body?frame??
  • ????????corr?+=?_q.conjugate_inversed(Vector<3>(0.0f,?0.0f,?-mag_err))?*?_w_mag;?//n系到b系??
  • ????}??
  • ? ? ? ? _w_mag為mag的權(quán)重。PS:發(fā)現(xiàn)一個(gè)規(guī)律,在不太理解C++的情況下看代碼的算法過程中經(jīng)常性的不知道某行代碼是做什么的,在哪定義的,比如這個(gè)Vector<3>,前面已經(jīng)介紹過它了,只要有它這樣的做前綴的,后面的變量就是類似int定義一個(gè)變量一樣,幾乎都在PX4Firmware/src/lib/mathlib/math/Quaternion.hpp中,進(jìn)行實(shí)例展開的。磁力計(jì)數(shù)據(jù)為_mag。mag_earth= _q.conjugate(_mag),這行代碼的含義為先將歸一化的_q的旋轉(zhuǎn)矩陣R(b系轉(zhuǎn)n系)乘以_mag向量(以自身機(jī)體坐標(biāo)系為視角看向北方的向量表示),得到n系(NED坐標(biāo)系)下的磁力計(jì)向量。如下就是conjugate函數(shù),其過程就是實(shí)現(xiàn)從b系到n系的轉(zhuǎn)換,使用左乘。

    [plain] view plain copy
  • /**??
  • ?????*?conjugation//b系到n系??
  • ?????*/??
  • ????Vector<3>?conjugate(const?Vector<3>?&v)?const?{??
  • ????????float?q0q0?=?data[0]?*?data[0];??
  • ????????float?q1q1?=?data[1]?*?data[1];??
  • ????????float?q2q2?=?data[2]?*?data[2];??
  • ????????float?q3q3?=?data[3]?*?data[3];??
  • ????????return?Vector<3>(??
  • ????????????????v.data[0]?*?(q0q0?+?q1q1?-?q2q2?-?q3q3)?+??
  • ????????????????v.data[1]?*?2.0f?*?(data[1]?*?data[2]?-?data[0]?*?data[3])?+??
  • ????????????????v.data[2]?*?2.0f?*?(data[0]?*?data[2]?+?data[1]?*?data[3]),??
  • ??
  • ????????????????v.data[0]?*?2.0f?*?(data[1]?*?data[2]?+?data[0]?*?data[3])?+??
  • ????????????????v.data[1]?*?(q0q0?-?q1q1?+?q2q2?-?q3q3)?+??
  • ????????????????v.data[2]?*?2.0f?*?(data[2]?*?data[3]?-?data[0]?*?data[1]),??
  • ??
  • ????????????????v.data[0]?*?2.0f?*?(data[1]?*?data[3]?-?data[0]?*?data[2])?+??
  • ????????????????v.data[1]?*?2.0f?*?(data[0]?*?data[1]?+?data[2]?*?data[3])?+??
  • ????????????????v.data[2]?*?(q0q0?-?q1q1?-?q2q2?+?q3q3)??
  • ????????);??
  • ????}??
  • ????mag_err?=?_wrap_pi(atan2f(mag_earth(1),?mag_earth(0))?-?_mag_decl);??
  • ? ? ? ? 只考慮Vector<3> mag_earth中的前兩維的數(shù)據(jù)mag_earth(1)和mag_earth(0)(即x、y,忽略z軸上的偏移),通過arctan(mag_earth(1),mag_earth(0))得到的角度和前面根據(jù)經(jīng)緯度獲取的磁偏角做差值得到糾偏誤差角度mag_err ,_wrap_pi函數(shù)是用于限定結(jié)果-pi到pi的函數(shù),源碼如下。

    [plain] view plain copy
  • __EXPORT?float?_wrap_pi(float?bearing)??
  • {??
  • ????/*?value?is?inf?or?NaN?*/??
  • ????if?(!isfinite(bearing))?{??
  • ????????return?bearing;??
  • ????}??
  • ????int?c?=?0;??
  • //大于pi則與2pi做差取補(bǔ)??
  • ????while?(bearing?>=?M_PI_F)?{//M_PI_F==3.14159265358979323846f??
  • ????????bearing?-=?M_TWOPI_F;//M_TWOPI_F==2*M_PI_F??
  • ????????if?(c++?>?3)?{??
  • ????????????return?NAN;//NaN==not?a?number??
  • ????????}??
  • ????}??
  • ????c?=?0;??
  • //小于-pi則與2pi做和取補(bǔ)??
  • ????while?(bearing?<?-M_PI_F)?{??
  • ????????bearing?+=?M_TWOPI_F;??
  • ????????if?(c++?>?3)?{??
  • ????????????return?NAN;??
  • ????????}??
  • ????}??
  • ????return?bearing;??
  • }??
  • 類似的約束函數(shù)都在src/lib/geo/geo.c中,比如:??
  • __EXPORT?float?_wrap_180(float?bearing);??
  • __EXPORT?float?_wrap_360(float?bearing);??
  • __EXPORT?float?_wrap_pi(float?bearing);??
  • __EXPORT?float?_wrap_2pi(float?bearing);??
  • ? ? ? ? ?corr +=_q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mag_err)) * _w_mag;//n系到b系

    ? ? ? ? ?計(jì)算corr值等于單位化的旋轉(zhuǎn)矩陣R(b系轉(zhuǎn)n系)的轉(zhuǎn)置(可以理解為 R(n系轉(zhuǎn)b系))乘以(0,0,-mag_err),相當(dāng)于機(jī)體坐標(biāo)系繞地理坐標(biāo)系N軸(Z軸)轉(zhuǎn)動(dòng)arctan(mag_earth(1), mag_earth(0))度。

    ? ? ? ? ?關(guān)于磁還需要更深入的了解,看相關(guān)論文吧,一大推~~~

    ? ? ? ? ?------------------------------------------------------------------------------------------------------------------------------

    ? ? ? ? 加速度計(jì)修正

    ? ? ? ? 首先就是把歸一化的n系重力加速度通過旋轉(zhuǎn)矩陣R左乘旋轉(zhuǎn)到b系,即k為歸一化的旋轉(zhuǎn)矩陣R(b-e)的第三行,代碼如下。

    [plain] view plain copy
  • //?Accelerometer?correction??
  • ????//?Project?'k'?unit?vector?of?earth?frame?to?body?frame??
  • ????//?Vector<3>?k?=?_q.conjugate_inversed(Vector<3>(0.0f,?0.0f,?1.0f));//?n系到b系??
  • ????//?Optimized?version?with?dropped?zeros??
  • ????Vector<3>?k(??
  • ????????2.0f?*?(_q(1)?*?_q(3)?-?_q(0)?*?_q(2)),??
  • ????????2.0f?*?(_q(2)?*?_q(3)?+?_q(0)?*?_q(1)),??
  • ????????(_q(0)?*?_q(0)?-?_q(1)?*?_q(1)?-?_q(2)?*?_q(2)?+?_q(3)?*?_q(3))??
  • ????);??
  • ? ? ? ? 上面這段代碼是不是很熟悉,還記得mahony算法中的的計(jì)算過程么?!都是一樣的,這里只是換種方式(C++)表達(dá),不在贅述。

    ? ? ? ? 下面這個(gè)比較重要:

    ? ? ? ??corr += (k %(_accel - _pos_acc).normalized()) * _w_accel

    ? ? ? ? {k%(_accel“加速度計(jì)的測(cè)量值”-位移加速度)的單位化)<約等于重力加速度g>}*權(quán)重。

    ? ? ? ? 關(guān)于這個(gè)“_accel-_pos_acc”的含義:

    ? ? ? ? 總的受到合力的方向(_accel)減去機(jī)體加速度方向(_pos_acc)得到g的方向,即總加速度(加速度獲取)減去機(jī)體運(yùn)動(dòng)加速度(第五部分)獲取重力加速度,然后姿態(tài)矩陣的不是行就是列來與純重力加速度來做叉積,算出誤差。因?yàn)檫\(yùn)動(dòng)加速度是有害的干擾,必須減掉。算法的理論基礎(chǔ)是[0,0,1]與姿態(tài)矩陣相乘。該差值獲取的重力加速度的方向是導(dǎo)航坐標(biāo)系下的z軸,加上運(yùn)動(dòng)加速度之后,總加速度的方向就不是與導(dǎo)航坐標(biāo)系的天或地平行了,所以要消除這個(gè)誤差,即“_accel-_pos_acc”。然后叉乘z軸向量得到誤差,進(jìn)行校準(zhǔn) 。

    ? ? ? ? 關(guān)于%運(yùn)算符在vector.hpp中介紹了其原型:

    [plain] view plain copy
  • Vector<3>?operator?%(const?Vector<3>?&v)?const?{??
  • ????????return?Vector<3>(??
  • ???????????????????data[1]?*?v.data[2]?-?data[2]?*?v.data[1],??
  • ???????????????????data[2]?*?v.data[0]?-?data[0]?*?v.data[2],??
  • ???????????????????data[0]?*?v.data[1]?-?data[1]?*?v.data[0]??
  • ???????????????);??
  • ????}??
  • };??
  • ? ? ? ?“ %”其實(shí)就是求向量叉積,叉積公式如下。

    ? ? ? ? ---------------------------------------------------------------------------------------------------------------------------------

    ? ? ? ? _gyro_bias+= corr * (_w_gyro_bias * dt);PI控制器中的I(積分)效果。然后對(duì)_gyro_bias做約束處理。

    [plain] view plain copy
  • for?(int?i?=?0;?i?<?3;?i++)?{??
  • ????????_gyro_bias(i)?=?math::constrain(_gyro_bias(i),?-_bias_max,?_bias_max);??
  • ????}??
  • ? ? ? ? 對(duì)偏移量進(jìn)行約束處理,源碼寫的相當(dāng)好啊,簡單易懂,其函數(shù)原型是:

    [plain] view plain copy
  • uint64_t?__EXPORT?constrain(uint64_t?val,?uint64_t?min,?uint64_t?max)??
  • {??
  • ??????return?(val?<?min)???min?:?((val?>?max)???max?:?val);??
  • }??
  • ? ? ? ? ---------------------------------------------------------------------------------------------------------------------------------

    ? ? ? ? 最后就是使用修正的數(shù)據(jù)更新四元數(shù),并把_rates和_gyro_bias置零便于下次調(diào)用時(shí)使用。

    [plain] view plain copy
  • _rates?=?_gyro?+?_gyro_bias;?//得到經(jīng)過修正后的角速度??
  • ????//?Feed?forward?gyro??
  • ????corr?+=?_rates;//PI控制器的體現(xiàn)??
  • ????//?Apply?correction?to?state??
  • ????_q?+=?_q.derivative(corr)?*?dt;//736??
  • ????//?Normalize?quaternion??
  • ????_q.normalize();??
  • ????if?(!(PX4_ISFINITE(_q(0))?&&?PX4_ISFINITE(_q(1))?&&??
  • ??????????PX4_ISFINITE(_q(2))?&&?PX4_ISFINITE(_q(3))))?{??
  • ????????//?Reset?quaternion?to?last?good?state??
  • ????????_q?=?q_last;??
  • ????????_rates.zero();??
  • ????????_gyro_bias.zero();??
  • ????????return?false;??
  • ????}??
  • ????return?true;??
  • ? ? ? ? 上面736行的_q += _q.derivative(corr) * dt非常重要,又用到了微分方程離散化的思想。以前講過DCM矩陣更新過程中也是用到了該思想。先看看代碼,有點(diǎn)怪,怪就怪在derivative(衍生物)這個(gè)名字上,平時(shí)一大推的論文和期刊上面都是用的omga *Q 的形式,而這里的代碼實(shí)現(xiàn)確是用的Q * omga的形式,所以構(gòu)造的4*4矩陣的每一列的符號(hào)就不一樣了。

    [plain] view plain copy
  • /***?derivative*/??
  • ????const?Quaternion?derivative(const?Vector<3>?&w)?{??
  • ????????float?dataQ[]?=?{??
  • ????????????data[0],?-data[1],?-data[2],?-data[3],??
  • ????????????data[1],??data[0],?-data[3],??data[2],??
  • ????????????data[2],??data[3],??data[0],?-data[1],??
  • ????????????data[3],?-data[2],??data[1],??data[0]??
  • ????????};??
  • ????????Matrix<4,?4>?Q(dataQ);??
  • ????????Vector<4>?v(0.0f,?w.data[0],?w.data[1],?w.data[2]);??
  • ????????return?Q?*?v?*?0.5f;??
  • ????}??
  • ? ? ? ? 這一部分理論基礎(chǔ)在《捷聯(lián)慣性導(dǎo)航技術(shù)》中有詳細(xì)介紹,關(guān)于DCM隨時(shí)間傳遞的推導(dǎo)過程、四元數(shù)隨時(shí)間傳遞的推導(dǎo)以及DCM、歐拉角、四元數(shù)之間的相互關(guān)系都有詳細(xì)的介紹。

    ? ? ? ? 總結(jié)一下:corr包含磁力計(jì)修正、加速度計(jì)修正、(vision、mocap修正)、gyro中測(cè)量到的角速度偏轉(zhuǎn)量,且因?yàn)閏orr為update函數(shù)中定義的變量,所以每次進(jìn)入update函數(shù)中時(shí)會(huì)刷新corr變量的數(shù)據(jù); _rate也會(huì)刷新其中的數(shù)據(jù),含義為三個(gè)姿態(tài)角的角速度(修正后); _q為外部定義的變量,在這個(gè)函數(shù)中只會(huì)+=不會(huì)重新賦值,如果計(jì)算出現(xiàn)錯(cuò)誤會(huì)返回上一次計(jì)算出的_q。

    ? ? ? ? ---------------------------------------------------------------------------------------------------------------------------------

    7、將_q轉(zhuǎn)換成歐拉角euler并發(fā)布(532)

    ? ? ? ? 終于從updata函數(shù)出來了,它還是相當(dāng)重要的,主要就是它了,需要深入的理解透徹,下面就是些小角色了。Updata函出來就是直接用一更新的四元數(shù)(_q)求出對(duì)于的歐拉角,以便在控制過程中實(shí)現(xiàn)完美的控制,控制還是需要用直接明了的歐拉角。上源碼:

    [plain] view plain copy
  • Vector<3>?euler?=?_q.to_euler();??
  • ????????struct?vehicle_attitude_s?att?=?{};??
  • ????????att.timestamp?=?sensors.timestamp;??
  • ????????att.roll?=?euler(0);//獲取的歐拉角賦值給roll、pitch、yaw??
  • ????????att.pitch?=?euler(1);??
  • ????????att.yaw?=?euler(2);??
  • ??
  • ????????att.rollspeed?=?_rates(0);?//獲取roll、pitch、yaw得旋轉(zhuǎn)速度??
  • ????????att.pitchspeed?=?_rates(1);??
  • ????????att.yawspeed?=?_rates(2);??
  • ????????for?(int?i?=?0;?i?<?3;?i++)?{??
  • ????????????att.g_comp[i]?=?_accel(i)?-?_pos_acc(i);???
  • //獲取導(dǎo)航坐標(biāo)系的重力加速度,前面已介紹過??
  • ????????}??
  • ? ? ? ? 比較重要的就是如何由四元數(shù)獲取歐拉角:_q.to_euler()

    [plain] view plain copy
  • /**??
  • ?????*?create?Euler?angles?vector?from?the?quaternion??
  • ?????*/??
  • ????Vector<3>?to_euler()?const?{??
  • ????????return?Vector<3>(??
  • ????????????atan2f(2.0f?*?(data[0]?*?data[1]?+?data[2]?*?data[3]),?1.0f?-?2.0f?*?(data[1]?*?data[1]?+?data[2]?*?data[2])),??
  • ????????????asinf(2.0f?*?(data[0]?*?data[2]?-?data[3]?*?data[1])),??
  • ????????????atan2f(2.0f?*?(data[0]?*?data[3]?+?data[1]?*?data[2]),?1.0f?-?2.0f?*?(data[2]?*?data[2]?+?data[3]?*?data[3]))??
  • ????????);??
  • ????}??
  • ? ? ? ? 下面的就比較好理解了,不在贅述。

    [plain] view plain copy
  • if?(_att_pub?==?nullptr)?{??
  • ????????????_att_pub?=?orb_advertise(ORB_ID(vehicle_attitude),?&att);??
  • ????????}?else?{??
  • ????????????orb_publish(ORB_ID(vehicle_attitude),?_att_pub,?&att);??
  • ????????}??
  • ????????struct?control_state_s?ctrl_state?=?{};??
  • ????????ctrl_state.timestamp?=?sensors.timestamp;??
  • ????????/*?Attitude?quaternions?for?control?state?*/??
  • ????????ctrl_state.q[0]?=?_q(0);??
  • ????????ctrl_state.q[1]?=?_q(1);??
  • ????????ctrl_state.q[2]?=?_q(2);??
  • ????????ctrl_state.q[3]?=?_q(3);??
  • ????????/*?Attitude?rates?for?control?state?*/??
  • ????????ctrl_state.roll_rate?=?_lp_roll_rate.apply(_rates(0));??
  • ????????ctrl_state.pitch_rate?=?_lp_pitch_rate.apply(_rates(1));??
  • ????????ctrl_state.yaw_rate?=?_lp_yaw_rate.apply(_rates(2));??
  • ????????/*?Publish?to?control?state?topic?*/??
  • ????????if?(_ctrl_state_pub?==?nullptr)?{??
  • ????????????_ctrl_state_pub?=?orb_advertise(ORB_ID(control_state),?&ctrl_state);??
  • ????????}?else?{??
  • ????????????orb_publish(ORB_ID(control_state),?_ctrl_state_pub,?&ctrl_state);??
  • ????????}??
  • 六、總結(jié)
    ? ? ? ? 通過上面的分析對(duì)ardupilot源代碼中的姿態(tài)解算算法有了深一步的了解,還有一部分就是關(guān)于mag的,還需要看一些論文,磁是最不容易處理的,極易受到外部干擾。還有就是加速度計(jì)的數(shù)據(jù),對(duì)震動(dòng)比較敏感,所以在無人機(jī)裝機(jī)時(shí)需要在pixhawk下面安裝減震板,做減震處理。
    ? ? ? ? 基本的姿態(tài)解算和飛行控制靠陀螺儀和加速計(jì)等肯定可以實(shí)現(xiàn),代碼也比較好寫,可以基于mahony的那套算法,硬件部分就是選定芯片,確定通信接口;然后移植一套免費(fèi)的OS即可。但是難得就是飛行時(shí)的穩(wěn)定性和對(duì)震動(dòng)和噪聲的處理問題,這些都是最細(xì)節(jié)最重要的部分,也是最難的部分。
    ? ? ? ? 接下來就是關(guān)于姿態(tài)控制的了,至少一個(gè)多禮拜的時(shí)間才能搞明白吧;att_estimate、pos_estimate和att_control、pos_control這四個(gè)部分全部搞定需要下很大的功夫,慢慢搞吧,看論文吧,站在別人的肩膀上,加油~~~ ? ??
    ? ? ? ? 感謝Mr、青龍等群友的幫助~~~

    版權(quán)聲明:. https://blog.csdn.net/qq_21842557/article/details/51058206

    總結(jié)

    以上是生活随笔為你收集整理的Pixhawk之姿态解算篇(3)_源码姿态解算算法分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。