移植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系列手册里用到的第一版协议,这个是中文版,这个是官方英文版

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值