移植DynamixelSDK到Android平臺

背景

DynamixelSDK是ROBOTIS公司爲其Dynamixel電機系列開發的SDK,面向x86平臺的各種OS(Windows/Linux)和語言(C/C++/Java/Python)。因爲我們的機器人要全面轉向安卓,所以需要將該SDK移植到安卓平臺,前後花了2天時間,算是基本完成,記錄一下。

準備工作

  • Ubuntu 14.4 LTS
  • Android NDK bundle

創建源碼目錄結構

  1. 下載SDK源碼
  2. 創建一個名叫Dynamixel-android的空目錄,再在下面創建jni子目錄,然後將SDK_dir/c/目錄下的srcinclude子目錄拷貝到jni子目錄下面,
  3. 創建Android.mk文件和Application.mk文件
  4. 最終形成如下目錄樹結構
    源碼目錄樹結構

編寫mk文件

Android.mk內容

LOCAL_PATH := $(call my-dir)

#################################################

include $(CLEAR_VARS)

LOCAL_MODULE := dxl

LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := \
    src/dynamixel_sdk/group_bulk_read.c \
           src/dynamixel_sdk/group_bulk_write.c \
           src/dynamixel_sdk/group_sync_read.c \
           src/dynamixel_sdk/group_sync_write.c \
           src/dynamixel_sdk/packet_handler.c \
           src/dynamixel_sdk/port_handler.c \
           src/dynamixel_sdk/protocol1_packet_handler.c \
           src/dynamixel_sdk/protocol2_packet_handler.c \
           src/dynamixel_sdk_linux/port_handler_linux.c

LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
LOCAL_STATIC_LIBRARIES := cpufeatures

include $(BUILD_SHARED_LIBRARY)

$(call import-module,android/cpufeatures)

Application.mk內容

APP_ABI = armeabi
APP_PLATFORM = android-21

這裏着重提示下,Application.mk是告訴ndk-build程序整個so模塊
1. 想生成哪些ABI(我選的armeabi,你可以選armeabi-v7aarm64-v8a,或都選)
2. 想針對哪些Android平臺版本(很重要,不設置該選項會出現下面錯誤,可能是不同平臺SYSROOT裏的內容不一樣)

[armeabi] Compile thumb  : dxl <= port_handler_linux.c
/home/haipeng/projetcs/Dynamixel-android/jni/src/dynamixel_sdk_linux/port_handler_linux.c:42:10: fatal error: 'linux/serial.h' file not found
#include <linux/serial.h>
         ^
1 error generated.
make: *** [/home/haipeng/projetcs/Dynamixel-android/obj/local/armeabi/objs/dxl/src/dynamixel_sdk_linux/port_handler_linux.o] Error 1

編譯

  1. 指定環境變量NDK_PROJECT_PATH的值爲你剛纔創建的目錄export NDK_PROJECT_PATH=~/projetcs/Dynamixel-android
  2. 在任意目錄運行ndk-build命令
  3. $(NDK_PROJECT_PATH)/libs目錄可以找到libdxl.so文件

集成JNA

DynamixelSDK爲了方便Java用戶,提供了JNA的適配代碼,但是JNA因爲歷史久遠的原因,對Android的支持並不好,我們要解決它

編譯支持Android的JNA

根據JNA官網的這篇文章先編譯出支持Android的JNA,編譯前記得 安裝autoconf 軟件包,否則ant -Dos.prefix=android-arm dist運行過程中會報錯:autoreconf not found

將JNA集成到Android工程

ant編譯輸出在JNA_dir/dist/目錄下,有jna.jar和jna-min.jar兩個文件,二者的區別是前者包括各平臺(Linux、Windows、Android等)的庫文件(.a/.dll/.so),後者沒有(只有class文件)。

因爲Android的apk製作工具在編譯jar包時會跳過裏面的so文件,所以選用後者,同時將前者裏面android-arm架構的libjnidispatch.so拷貝到Android工程libs/armeabi目錄下,並在build.gradle裏添加相應語句,將其打包到apk裏去

在Android工程裏使用JNA

在用到JNA的類裏(比如MainActivity.java)添加

static {  
        System.loadLibrary("jnidispatch");  
    }  

集成

修改java/dynamixel_functions_java/x86/Dynamixel.java文件,將

LibFunction libFunction = (LibFunction)Native.loadLibrary(“dxl_x86_c”, LibFunction.class);

替換成

LibFunction libFunction = (LibFunction)Native.loadLibrary(“dxl”, LibFunction.class);

並將修改後的Dynamixel.java拷貝到demo工程src下適當目錄

最終Android dem應用工程裏至少包含5個關鍵文件:
+ DynamixelSDK的so文件、JNA適配文件(Dynamixel.java)
+ JNA的so文件、jna-min.jar
+ 根據Java版DynamixelSDK樣例程序編寫的demo類

推倒重來

集成完了運行,程序報錯說打不開串口設備,想起來Android對USB設備(包括USB串口)做了保護,必須通過Android USB Host API訪問才行,不能通過直接讀寫/dev/目錄下的設備文件來實現,所以DynamixelSDK裏大量的串口相關底層代碼完全無用,必須使用github上的usb-serial-for-android庫才行。

這裏涉及一個考量,是用usb-serial-for-android遷就Dynamixel的上層邏輯呢?還是Dynamixel遷就usb-serial-for-android的底層邏輯?考慮到Dynamixel的底層代碼與上層耦合很緊,而上層代碼的複雜度並沒有那麼高,所以決定拋棄Dynamixel的所有代碼,根據其開發手冊中描述的UART幀格式完全用Java實現一遍。

協議的Java實現就不貼了,可以參考AX-12系列手冊裏用到的第一版協議,這個是中文版,這個是官方英文版

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章