【问题标题】:Raspberry Pi - Interfacing with an i2c enabled IR temp sensor (MLX90614)Raspberry Pi - 与启用 i2c 的 IR 温度传感器 (MLX90614) 连接
【发布时间】:2016-03-09 00:50:33
【问题描述】:

所以我被招募到学校的 Baja 赛车队,在那里我们设计建造并与越野沙丘越野车竞争。我是一名 CS 专业的,对 python 有相当多的经验,因此被要求帮助电气团队与我们想要在汽车上安装的所有传感器进行接口。到目前为止一切都很好,但现在我正在使用一个红外温度传感器来读取环境和物体温度。 (我们将把它放在引擎的某个地方以读取它的温度并输出到我们的 GUI)

问题在于,似乎使用过这个传感器的唯一库都是用 C 语言编写的,并且通常与 arduinos 一起使用……尽管如此,我编译并编辑了一些我在网上找到的 C 代码,效果很好!在 C. :( 因为我们的项目完全基于 python;我真的很想通过 i2c 和 Python 来阅读这个传感器,虽然我真的没有很多编写库的经验,尤其是对于电子产品。任何提示会很好地引导我朝着正确的方向前进。这是我们目前使用的 C 代码,我基本上想要在 Python 中做同样的事情:

    //fordit:  gcc MLXi2c.c -o i2c -l bcm2835
#include <stdio.h>
#include <bcm2835.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include<time.h>
#define AVG 1   //averaging samples
#define LOGTIME 10  //loging period
int main(int argc, char **argv)
{
    unsigned char buf[6];
    unsigned char i,reg;
    double temp=0,calc=0, skytemp,atemp;
    FILE *flog;
    flog=fopen("mlxlog.csv", "a");..
    bcm2835_init();
    bcm2835_i2c_begin();
    bcm2835_i2c_set_baudrate(25000);.
    // set address...........................................................................................
    bcm2835_i2c_setSlaveAddress(0x5a);
....
    printf("\nOk, your device is working!!\n");
....
....
    while(1) {
        time_t t = time(NULL);
<------>struct tm tm = *localtime(&t);
<------>calc=0;
<------>reg=7;
<------>for(i=0;i<AVG;i++){
<------>    bcm2835_i2c_begin();
<------>    bcm2835_i2c_write (&reg, 1);
<------>    bcm2835_i2c_read_register_rs(&reg,&buf[0],3);
<------>    temp = (double) (((buf[1]) << 8) + buf[0]);
<------>    temp = (temp * 0.02)-0.01;
    <-->    temp = temp - 273.15;
<------>    calc+=temp;
<------>    sleep(1);
<------>    }
<------>skytemp=calc/AVG;
<------>calc=0;
<------>reg=6;
<------>for(i=0;i<AVG;i++){
<------>    bcm2835_i2c_begin();
<------>    bcm2835_i2c_write (&reg, 1);
<------>    bcm2835_i2c_read_register_rs(&reg,&buf[0],3);
<------>    temp = (double) (((buf[1]) << 8) + buf[0]);
<------>    temp = (temp * 0.02)-0.01;
    <-->    temp = temp - 273.15;
<------>    calc+=temp;
<------>    sleep(1);
<------>    }
<------>atemp=calc/AVG;
<------>printf("%02d-%02d %02d:%02d:%02d\n    Tambi=%04.2f C, Tobj=%04.2f C\n", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,atemp,skytemp);
<------>fprintf(flog,"%04d-%02d-%02d %02d:%02d:%02d,%04.2f,%04.02f\n",tm.tm_year+1900, tm.tm_mon +1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec,atemp,skytemp);
<------>fflush(flog);
<------>sleep(LOGTIME-(2*AVG));
    }
...
    printf("[done]\n");
}

提前致谢!

  • 艾迪

【问题讨论】:

  • 为什么不直接从python调用C程序而不是重写整个东西?
  • 我不知道你能做到这一点?你介意详细说明吗?我其实想过这个,如果我能以某种方式将 C 程序的返回值导入 python,我会很高兴。
  • 如果你有一个不能无限运行的程序,它就像import subprocess; sens_val = subprocess.check_output(["path_to_your_c_program"]) 一样简单如果你的 C 程序确实可以无限运行(例如,在 while(1) 循环中,就像在 arduino 上一样),您可以简单地删除该循环,使其每次执行仅获取一个传感器读数,将其打印到标准输出并退出。

标签: python raspberry-pi


【解决方案1】:

变化:

  • 删除了while(1) - 每次执行只有一个读数。如果传感器需要重复启动,则可能需要一个 for/while 循环;除非你打算从 python 中终止进程,否则不要让它成为无限循环。
  • 最后一个 printf 现在输出一个由开始和结束管道分隔的 JSON 字符串/|
  • return 0; 添加到main(),这样python 的子进程模块就知道了 怎么了
  • 删除了导致编译器错误的 cmets 和句号(低级 C 专家,句号重要吗?)

将其保存为 mlx90614_query.c 并编译:

//fordit:  gcc mlx90614_query.c -o mlx90614_query -l bcm2835
#include <stdio.h>
#include <bcm2835.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#define AVG 1   //averaging samples
#define LOGTIME 10  //loging period

int main(int argc, char **argv)
{
    unsigned char buf[6];
    unsigned char i,reg;
    double temp=0,calc=0, skytemp,atemp;
    FILE *flog;
    flog=fopen("mlxlog.csv", "a");
    bcm2835_init();
    bcm2835_i2c_begin();
    bcm2835_i2c_set_baudrate(25000);
    // set address
    bcm2835_i2c_setSlaveAddress(0x5a);

    printf("\nOk, your device is working!!\n");

    time_t t = time(NULL);
    struct tm tm = *localtime(&t);
    calc=0;
    reg=7;

    for(i=0;i<AVG;i++){
        bcm2835_i2c_begin();
        bcm2835_i2c_write (&reg, 1);
        bcm2835_i2c_read_register_rs(&reg,&buf[0],3);
        temp = (double) (((buf[1]) << 8) + buf[0]);
        temp = (temp * 0.02)-0.01;
        temp = temp - 273.15;
        calc+=temp;
        sleep(1);
    }

    skytemp=calc/AVG;
    calc=0;
    reg=6;

    for(i=0;i<AVG;i++){
        bcm2835_i2c_begin();
        bcm2835_i2c_write (&reg, 1);
        bcm2835_i2c_read_register_rs(&reg,&buf[0],3);
        temp = (double) (((buf[1]) << 8) + buf[0]);
        temp = (temp * 0.02)-0.01;
        temp = temp - 273.15;
        calc+=temp;
        sleep(1);
    }

    atemp=calc/AVG;

    printf("|{\"time\":{\"month\":\"%02d\",\"day\":\"%02d\",\"hour\":\"%02d\",\"min\":\"%02d\",\"sec\":\"%02d\"},\"data\":{\"t_ambi\":\"%04.2f\",\"t_obj\":\"%04.2f\"}}|\n", tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,atemp,skytemp);

    fprintf(flog,"%04d-%02d-%02d %02d:%02d:%02d,%04.2f,%04.02f\n",tm.tm_year+1900, tm.tm_mon +1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec,atemp,skytemp);

    fflush(flog);
    sleep(LOGTIME-(2*AVG));

    printf("[done]\n");

    return 0;
}

您的 C 程序现在输出您现有的调试消息以及此 json(“|”用作分隔符):

{
    "time": {
        "month": "03",
        "day": "09",
        "hour": "20",
        "min": "24",
        "sec": "28"
    },
    "data": {
        "t_ambi": "77.77",
        "t_obj": "34.44"
    }
}

将此作为 python 脚本保存在与 mlx90614_query 相同的文件夹中(如果您复制/粘贴到交互式解释器,多余的空格会导致麻烦):

from __future__ import print_function
import json
import subprocess
import sys

sensor_dict = {}

py3 = False

# python version check determines string handling

try:
    if (sys.version_info > (3, 0)):
        py3 = True    
except:
    pass

try:

    subp_ret = subprocess.check_output(["./mlx90614_query"])

    # at this point, subprocess succeeded and subp_ret holds your output 

    if py3:
        subp_ret = subp_ret.decode('utf8')

    sensor_dict = json.loads(subp_ret.split("|")[1].strip())

    # cast temperatures to float and print

    for k in sensor_dict["data"]:
        val = float(sensor_dict["data"][k]) 
        sensor_dict["data"][k] = val  
        print (k, "\t", val) 

    # cast date/time segments to int and print

    for k in sensor_dict["time"]:
        val = int(sensor_dict["time"][k])
        sensor_dict["time"][k] = val  
        print (k, "\t", val)         

    # Now go win that race! :P

except Exception as e:
    print(str(e))

输出:

$ gcc mlx90614_query.c -o mlx90614_query -l bcm2835
$

$ ./mlx90614_query
Ok, your device is working!!
|{"time":{"month":"03","day":"09","hour":"21","min":"45","sec":"53"},"data":{"t_ambi":"0.00","t_obj":"0.00"}}|
[done]


$ python3.4 mlx_print.py 
t_obj    34.44
t_ambi   77.77
hour     21
sec      33
min      58
month    3
day      9

$ python2 mlx_print.py 
t_ambi   77.77
t_obj    34.44
min      58
sec      37
day      9
hour     21
month    3

很抱歉偷了你的作业 - 只需

【讨论】:

  • 非常感谢!团队真诚地感谢您。虽然有一个问题,有没有办法可以加快速度?当我运行 mlx_print.py 时,实际输出任何数据需要大约 10 秒,这与采样平均值有关吗?谢谢你
  • 不客气 :) 不过延迟很奇怪。我没有进入低级 i2C 的东西,也没有你的传感器,所以我也不能做太多的测试。这可能是抽样平均值,但从我的立场很难说 - 我会看看互联网是否有更多关于此事的信息。当我用一些随机的硬编码值运行 script + c 程序时,它立即返回。您是否尝试过几次单独运行 c 程序?没有python脚本会延迟吗?总是?
  • 尝试编译this one,看看它是否有任何改变。这次我实际上只删除了while循环并添加了return语句;没有清理或其他任何东西(我上次可能引入了一个微妙的错误)。您可能可以摆脱sleep(LOGTIME-(2*AVG));,但请先按原样尝试。
  • 编译/usr/bin/ld时出错:找不到-lbcm2835
猜你喜欢
  • 1970-01-01
  • 2018-07-29
  • 2018-04-08
  • 2017-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 2022-06-10
  • 2021-02-25
相关资源
最近更新 更多