基于libpcan库can总线操作的Barrett 机械手控制及腕部六维力传感器驱动

发布时间:2017年08月10日 18:10:58    浏览数:299次    来自:信雪神话
通过can总线直接向机械手控制器发送控制指令,实现机械手闭合控制,同时实现六维力传感器数据实时监测。

效果:

通过can总线直接向机械手控制器发送控制指令,实现机械手闭合控制,同时实现六维力传感器数据实时监测。

环境:ubuntu14.04+ROS indigo+pcan驱动(插入pcan后,能够使用ls /dev/pcan*显示出端口名称)。

正文:

    通过libpcan库操作can总线实现数据发送、读取,按照机械手控制器的数据格式要求,即可实现机械手和六维力传感器的驱动。可以通过两种方法获得机械手和六维力传感器个数据格式:其一是通过在控制机械手同时,外接一根pcan usb到windows下PcanView软件观察总结机械手控制时的数据格式,然后进行模仿,该方法较为直接,但是需要将数据和机械手控制所用的角速度、角度等信息进行对应,因此需要一定的经验。其二是从barrett的节点文件barrett_hand-indigo-devel/bhand_controller/src/bhand_controller/下的bhand_node.py,pyHand_api.py入手,找到其与机械手操作相关的函数或类的数据格式定义。而六维力传感器的数据格式及初始化操作要从MonitorForceTorque.cpp中分析得到。 

3.2.1 显式调用libpcan.so 动态链接库实现can总线操作

下面给出一个libcan库的操作例子,本例博文地址:

http://blog.csdn.net/hookie1990/article/details/52629043

http://rosclub.cn/post-1018.html

1、添加载入需要的头文件及文件中自己使用的头文件。载入相关的头文件为dlfcn.h,fcntl.h,由于目标使用libpcan函数,所以libpcan.h也要加入。

l  dlfcn.h : Linux动态库的显式调用库,包括dlopen(),dlclose()等。

l  fcntl.h :fcntl.h定义了很多宏和open,fcntl函数原型,包括close open等关闭文件的系列操作。本文中用到了其打开文件的宏定义,即打开文件的控制模式。

    int open(const char*pathname, int oflag, ... /* mode_t mode */);
  返回值:成功则返回文件描述符,否则返回 -1
  对于open函数来说,第三个参数(...)仅当创建新文件时(即使用了O_CREAT 时)才使用,用于指定文件的访问权限位(access permission bits)。pathname是待打开/创建文件的路径名(如 C:/cpp/a.cpp);oflag用于指定文件的打开/创建模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成。
  O_RDONLY 只读模式
  O_WRONLY 只写模式
  O_RDWR 读写模式
  打开/创建文件时,至少得使用上述三个常量中的一个。以下常量是选用的:
  O_APPEND 每次写操作都写入文件的末尾
  O_CREAT 如果指定文件不存在,则创建这个文件
  O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改errno 的值
  O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容(即将其长度截短为0)
  O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
  O_NONBLOCK 如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblockingmode)
  以下三个常量同样是选用的,它们用于同步输入输出
  O_DSYNC 等待物理 I/O 结束后再write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
  O_RSYNC read 等待所有写入同一区域的写操作完成后再进行
  O_SYNC 等待物理 I/O 结束后再write,包括更新文件属性的 I/O open 返回的文件描述符一定是最小的未被使用的描述符。

2、根据目标使用的函数及其参数形式定义目标指针。

    此处暂时使用两个函数,一个CAN_Init,一个LINUX_CAN_Open函数。

    下面为libpcan.h头文件中的定义。

DWORD CAN_Init(HANDLE hHandle, WORD wBTR0BTR1, int nCANMsgType);  
HANDLE LINUX_CAN_Open(const char *szDeviceName, int nFlag);

根据上面定义我们声明两个函数指针的类型,方便后文使用

//define mapping function according to target function in libpcan.h  
typedef DWORD (*funCAN_Init_TYPE)(HANDLE hHandle, WORD wBTR0BTR1, int nCANMsgType);  
typedef HANDLE (*funLINUX_CAN_Open_TYPE)(const char *szDeviceName, int nFlag);

3、定义文件访问访问的指针,实现文件加载。

void *libm_handle = NULL;//define pointer used for file acess of libpcan.so  
 // dlopen 函数还会自动解析共享库中的依赖项。这样,如果您打开了一个依赖于其他共享库的对象,它就会自动加载它们。  
 // 函数返回一个句柄,该句柄用于后续的 API 调用  
libm_handle = dlopen("libpcan.so", RTLD_LAZY );  
 // 如果返回 NULL 句柄,表示无法找到对象文件,过程结束。否则的话,将会得到对象的一个句柄,可以进一步询问对象  
 if (!libm_handle){  
    // 如果返回 NULL 句柄,通过dlerror方法可以取得无法访问对象的原因  
    printf("Open Error:%s.\n",dlerror());  
    return 0;  
 }

其中用到的dlopen的参数解释如下:

void *dlopen(const char *filename, intflag);

其中flag有:RTLD_LAZYRTLD_NOW RTLD_GLOBAL,其含义分别为:

RTLD_LAZY:在dlopen返回前,对于动态库中存在的未定义的变量(如外部变量extern,也可以是函数)不执行解析,就是不解析这个变量的地址。

RTLD_NOW:与上面不同,他需要在dlopen返回前,解析出每个未定义变量的地址,如果解析不出来,在dlopen会返回NULL,错误为:undefined symbol: xxxx.......

RTLD_GLOBAL:它的含义是它的含义是使得库中的解析的定义变量在随后的随后其它的链接库中变得可以使用。

4、实现动态库函数到目标函数的映射。

// 使用 dlsym 函数,尝试解析新打开的对象文件中的符号。您将会得到一个有效的指向该符号的指针,或者是得到一个 NULL 并返回一个错误  
//one-to-one mapping  
char *errorInfo;//error information pointer  
fun_CAN_Init =(funCAN_Init_TYPE)dlsym(libm_handle,"CAN_Init");  
funLINUX_CAN_Open = (funLINUX_CAN_Open_TYPE)dlsym(libm_handle,"LINUX_CAN_Open");  
errorInfo = dlerror();// 调用dlerror方法,返回错误信息的同时,内存中的错误信息被清空  
 if (errorInfo != NULL){  
    printf("Dlsym Error:%s.\n",errorInfo);  
    return 0;  
 }

5、定义访问硬件的HANDLE(指针),实现自定义函数对于can总线的访问,访问完成要关闭对象。

    此前文中已有定义。

#define DEFAULT_NODE "/dev/pcan0"

    此处实现如下:

HANDLE pcan_handle =NULL;//void *pcan_handle  
  
const char  *szDevNode = DEFAULT_NODE;//define const pointer point to device name  
pcan_handle = funLINUX_CAN_Open(szDevNode, O_RDWR | O_NONBLOCK);//use mapping function  
//judge whether the call is success.if pcan_handle=null,the call would be failed  
if(pcan_handle)
{  
    can_set_init();  
    printf("receivetest: %s have been opened\n", szDevNode);  
}  
 else  
     printf("receivetest: can't open %s\n", szDevNode);  
  
 // 调用 ELF 对象中的目标函数后,通过调用 dlclose 来关闭对它的访问  
dlclose(libm_handle);

    最终映射使用的函数如下:

    funCAN_Init         =(funCAN_Init_TYPE)        dlsym(libm_handle,"CAN_Init");

    funLINUX_CAN_Open   =(funLINUX_CAN_Open_TYPE)  dlsym(libm_handle,"LINUX_CAN_Open");

    funCAN_Close        =(funCAN_Close_TYPE)        dlsym(libm_handle,"CAN_Close");

    funCAN_VersionInfo    =(funCAN_VersionInfo_TYPE) dlsym(libm_handle,"CAN_VersionInfo");

    funLINUX_CAN_Read  =(funLINUX_CAN_Read_TYPE)  dlsym(libm_handle,"LINUX_CAN_Read");

    funCAN_Status       =(funCAN_Status_TYPE)      dlsym(libm_handle,"CAN_Status");

    funnGetLastError       =(funnGetLastError_TYPE)   dlsym(libm_handle,"nGetLastError");

    funCAN_Write       =(funCAN_Write_TYPE)       dlsym(libm_handle,"CAN_Write");


标签: ROSClubpcan

评论共0条评论

登录后再评论!

全部评论

目前没有评论