我是靠谱客的博主 愤怒银耳汤,最近开发中收集的这篇文章主要介绍python调用.c遇到的一些问题及解决方法(读取ATI六维力传感器测得数据)前言一、使用ctypes外部函数库二、编译.c程序在python中调用总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

python调用.c遇到的一些问题及解决方法(读取ATI六维力传感器测得数据)

  • 前言
  • 一、使用ctypes外部函数库
  • 二、编译.c程序在python中调用
    • 1.编译.c程序
    • 2.python中调用
    • 3.使用.c程序中的局部变量
  • 总结

前言

工作需要读取六维力传感器测得的数据,现有一个ATI公司提供的.c的程序可以读取ait mini45的数据,因为想要在python里做数据的处理,把.c改成python也需要大量的时间精力,而且c执行的速度也要比python快不是一点半点,所以用到python调用c动态库。


一、使用ctypes外部函数库

from ctypes import *

ctypes官方文档
ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.

谷歌翻译:ctypes是Python的外部函数库。 它提供C兼容的数据类型,并允许在DLL或共享库中调用函数。 它可以用于将这些库包装在纯Python中。

二、编译.c程序在python中调用

1.编译.c程序

因为我是在linux环境下编译使用的,所以要编译成.so文件(Windows下需要编译为.dll文件)。

在命令行输入

gcc net.c -shared -o net.so

但我的电脑会报错
在这里插入图片描述
所以输入

gcc net.c -shared -o net.so -std=c99 -fPIC

编译成功
根据.c文件名称不同更改net.c。

2.python中调用

直接使用ctypes的方法LoadLibrary。

# python端代码
from ctypes import *
library = cdll.LoadLibrary("./net.so")
library.main()
//c 端代码
#inclue <stdio.h>
void main(){
print("*****************")
}

执行结果

在这里插入图片描述
至此已经成功调用c语言程序


3.使用.c程序中的局部变量

这里是我卡的最久的地方,因为我需要的数据在c里是一个数组,可以在执行c的时候printf打印出来,但是我不知道如何在python中使用这些数据。
需要的数据是六维力传感器六个维度的测量值:

虽然是用python执行打印出来的,但是这些是.c里的局部变量,执行完调用的c程序就没了。
一开始我尝试用return返回一个数组,python里面接收这个函数的返回值,但是怎么弄都只能接受int类型的返回值,也就只能返回数组里一个元素的值。后来把打算把这些数据转换为str字符串的类型,中间使用“ ”或者“|”分隔开,然后进行返回。
结果还是以失败告终。
不断的查找资料,结果不是讲的太浅(没怎么将数据类型之间的转换),就是讲的太深,实在是看不懂别人的程序(因为我比较菜)。
最后找到了这一篇,非常感谢作者
Python调用c/c++动态库(一)
在这里插入图片描述
看到这个地方,才真正解决了我的问题,虽然我写的还是很low,但终于可以把我需要的数据送到python程序里了。
下面是ATI提供的.c程序,我仅仅修改了主函数的输入值,以便输出给我python程序,最下面注释掉的部分是我尝试的过程。

/* Simple demo showing how to communicate with Net F/T using C language. */
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define PORT 49152 /* Port the Net F/T always uses 通常使用端口*/
#define COMMAND 2 /* Command code 2 starts streaming 命令代码2开始流*/
/* Typedefs used so integer sizes are more explicit 使用Typedefs使整数大小明确*/
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char byte;
typedef struct response_struct {
uint32 rdt_sequence;
uint32 ft_sequence;
uint32 status;
int32 FTData[6];
} RESPONSE;
int main(int * a,int * b,int * c ,int * d,int * e,int * f) {
int socketHandle;
/* Handle to UDP socket used to communicate with Net F/T. 处理用于Net F/T通讯的UDP套接字*/
struct sockaddr_in addr;	/* Address of Net F/T. Net F/T的ip地址*/
struct hostent* he;
/* Host entry for Net F/T. Net F/T的主机条目*/
byte request[8];
/* The request data sent to the Net F/T. 发送到Net F/T的请求数据*/
RESPONSE resp;
/* The structured response received from the Net F/T. 从Net F/T接受到的结构体*/
byte response[36];
/* The raw response data received from the Net F/T. 从Net F/T接受到的原始数据*/
int i;
/* Generic loop/array index. 通用 环/数组 索引*/
int err;
/* Error status of operations. 操作错误状态*/
char* AXES[] = { "Fx", "Fy", "Fz", "Tx", "Ty", "Tz" };	/* The names of the force and torque axes. */
/* Calculate number of samples, command code, and open socket here. 计算样本数 命令代码
打开socket*/
socketHandle = socket(AF_INET, SOCK_DGRAM, 0);
if (socketHandle == -1) {
exit(1);
}
*(uint16*)&request[0] = htons(0x1234); /* standard header. 标准头*/
*(uint16*)&request[2] = htons(COMMAND); /* per table 9.1 in Net F/T user manual. 根据用户手册表9.1*/
*(uint32*)&request[4] = htonl(1); /* see section 9.1 in Net F/T user manual. 用户手册9.1节*/
/* Sending the request. 发送请求*/
he = gethostbyname("192.168.1.1");
memcpy(&addr.sin_addr, he->h_addr_list[0], he->h_length);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
err = connect(socketHandle, (struct sockaddr*)&addr, sizeof(addr));
if (err == -1) {
exit(2);
}
send(socketHandle, request, 8, 0);
/* Receiving the response. 接受响应*/
recv(socketHandle, response, 36, 0);
resp.rdt_sequence = ntohl(*(uint32*)&response[0]);
resp.ft_sequence = ntohl(*(uint32*)&response[4]);
resp.status = ntohl(*(uint32*)&response[8]);
for (i = 0; i < 6; i++) {
resp.FTData[i] = ntohl(*(int32*)&response[12 + i * 4]);
}
/* Output the response data. 输出响应数据*/
int guo[6];
//printf("Status: 0x%08xn", resp.status);
for (i = 0; i < 6; i++) {
printf("%s: %dtn", AXES[i], resp.FTData[i]);
guo[i] = resp.FTData[i];
}
*a = guo[0];
*b = guo[1];
*c = guo[2];
*d = guo[3];
*e = guo[4];
*f = guo[5];
return 0;
//	char str[50]={''};
//	char stm[50]={''};
//	for(int s = 0;s<6;s++)
//	{
//
sprintf(str,"%d",guo[s]);
//
strcat(stm,str);
//
strcat(stm,"+");
//	}
//	printf("%s",stm);
//	int a = atoi(stm);
//	printf("%d",a);
//	return a;
//	return "hello123132132131321321321321";
}

下面是python部分:

from ctypes import *
library = cdll.LoadLibrary("./netft.so")
sensorvalue = []
def sensor():
global sensorvalue
library.main.argtypes = [POINTER(c_int)]
library.main.restype = c_void_p
a = c_int(0)
b = c_int(0)
c = c_int(0)
d = c_int(0)
e = c_int(0)
f = c_int(0)
library.main(byref(a),byref(b),byref(c),byref(d),byref(e),byref(f))
print(a,b,c,d,e,f)
print(type(a))
sensorvalue = [a.value, b.value, c.value, d.value, e.value, f.value ]
print(sensorvalue[0])
sensor()
print(sensorvalue[1])

至此,获取到了我想要的传感器数值,六维度数据放在列表sensorvalue[6]里面了。

总结

以上是我调用.c遇到的一些问题,花费了很久才解决,主要是对c的指针和对python数据类型转换不够了解,将来也会好好学习这一部分。
下一阶段准备对这些数据进行使用,先做一个波形图,然后根据这些数据进行机器人姿态的调整。

更新:虚拟机一定要桥连!然后修改地址:
ifconfig ens33 192.168.1.2 up
就可以读取数值了

最后

以上就是愤怒银耳汤为你收集整理的python调用.c遇到的一些问题及解决方法(读取ATI六维力传感器测得数据)前言一、使用ctypes外部函数库二、编译.c程序在python中调用总结的全部内容,希望文章能够帮你解决python调用.c遇到的一些问题及解决方法(读取ATI六维力传感器测得数据)前言一、使用ctypes外部函数库二、编译.c程序在python中调用总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部