2016-03-09 111 views
0

因此,我被招募到我們學校的Baja賽車隊,在那裏我們設計構建並與越野沙丘車類型賽車競爭。我是CS專業大學畢業生,在Python方面有相當多的經驗,因此被要求幫助電氣團隊與我們想要的所有傳感器接口。到目前爲止這麼好,但現在我正在使用一個讀取環境溫度和物體溫度的紅外溫度傳感器。 (我們打算把它放在引擎上的某個地方讀取它的溫度並輸出到我們的GUI)Raspberry Pi - 與啓用i2c的紅外溫度傳感器(MLX90614)接口

問題是似乎只有使用這種傳感器的庫全部用C編寫,通常與arduinos一起使用...儘管如此,我編譯和編輯了一些我在網上找到的C代碼,它效果很好!在C. :(因爲我們的項目完全基於python;我真的很喜歡通過i2c和Python讀取這個傳感器的一些幫助,雖然我沒有很多編寫庫的經驗,尤其是對於電子學。提示將是巨大的,引導我在正確的方向下面是我們目前使用的我基本上要在Python同樣的事情的C代碼:!

//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"); 
} 

在此先感謝

  • 埃迪
+0

爲什麼不簡單地從Python中調用C程序而不是重寫整個事情呢? – jDo

+0

我不知道你能做到嗎?你介意闡述嗎? 我其實想到這個,如果我能從C程序中得到返回的值到Python,我會是金。 –

+0

如果你有一個不能無限運行的程序,就像'import subprocess; sens_val = subprocess.check_output([「path_to_your_c_program」]) 如果你的C程序運行無限(例如在一個'while(1)'循環中就像在arduino上一樣),你可以簡單地刪除那個循環,每次執行讀取一次傳感器讀數,將其打印到標準輸出並退出。 – jDo

回答

1

變化:

  • 刪除while(1) - 每次執行只有一個讀。如果傳感器需要重複啓動,則可能需要for/while循環;只是不要讓它成爲一個無限循環,除非你打算從python殺死進程。
  • 最後的printf現在輸出一個JSON字符串,由開始和結束管道/ |分隔。
  • 添加return 0;main()所以Python的子模塊知道 什麼事
  • 刪除評論和句號導致編譯器錯誤(低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 

對不起,竊取你的功課 - 只需< 3碼:d

+0

非常感謝!該團隊真誠地感謝你。雖然有一個問題,我有辦法加快速度嗎?當我運行mlx_print.py時,實際輸出任何數據需要10秒鐘,這是否與採樣平均值有關?謝謝你 –

+0

不客氣:)雖然有關延遲的奇怪。我沒有進入低級i2C的東西,沒有你的傳感器,所以我也做不了多少測試。這可能是抽樣平均數,但很難從我的立場說 - 我會看看互聯網是否有關於此事的更多信息。當我用一些隨機的硬編碼值運行腳本+ c程序時,它立即返回。您是否嘗試過幾次運行c程序?沒有python腳本會延遲嗎?總是? – jDo

+0

請嘗試編譯[this one](http://pastebin.com/raw/PnLVC44v)來查看它是否改變了任何內容。我從字面上只刪除了while循環,並且這次添加了return語句;沒有清理或其他任何東西(我可能在上次引入了一個微妙的錯誤)。你可以擺脫睡眠(LOGTIME-(2 * AVG));'但是首先嚐試它。編譯/ usr/bin/ld時出現錯誤 – jDo