RaspberryPi[26] プロセス間通信(shared memory)

複数のセンサーを読み込む場合、センサーの取り込み周期が異なる場合があります。そんな場合、一つのプロセス(プログラム)で作ると全体の速度に依存することがあります。そんな場合は、プロセスを分けるとプログラム自体が楽になり、処理速度も速くできます。今回、初めて共有メモリを介してデータを読むプログラムを書いてみました。

構成はこんな感じです。

GPSのNMEAから緯度経度、速度を算出、風速計から風速と風向を、IMUセンサーから姿勢と3次元加速度を得ます。風速は10Hz、IMUは50Hz、GPSは1Hzなのでそれぞれ別々にプロセスを作り、一番遅いGPSのタイミングでUDPで送信します。IMUを遅延なしで回すと50Hzと早いので50msecでIMUサンプリングをします。それらを移動平均計算し、GPSプロセスに共有メモリを介して姿勢と3次元加速度を渡します。このセンサーHATは他に温度センサーと色センサーも載っていますが、今回は使いませでした。風速計は10Hzなので、その周期で供給メモリに書き込みます。GPSプロセスが各データを受け取るために、それぞれのセンサー用に共有メモリを二つ用意します。一つは風速計用、もう一つはIMUセンサ用です。共有メモリのID(アドレス)はGPSプロセスが作成し、それをファイルとして保存します。風速とIMUはそのファイルを読み込み、そのIDが示す共有メモリにそれぞれのデータを書き込みます。そのため、起動順番はGPSプロセスを一番先に起動させます。また、GPS、IMUセンサーと風速センサーのデータはUSBにすべて記録します。

GPSプロセスは集めたデータを解析したのち、UDPを用いてGPSの受信周期でPCに送ります。PCではVB.NETで作成した表示プログラムで受信して表示させます。

GPSプロセスのコードです。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/socket.h> //socket()
#include <sys/ioctl.h>  //ioctl()
#include <arpa/inet.h>  //htons(), inet_addr()

#define SERIAL_PORT "/dev/ttyACM0"
#define SERIAL_PORT2 "/dev/ttyUSB0"

#define TRUE 1
#define FALSE 0
#define DATA_SIZE_WIND 256  // shared memory size for wind
#define DATA_SIZE_IMU  512  // shared memory size for imu
#define DATA_SIZE_UDP  512  // data size for udp
#define DATA_SIZE_CMN  255

const int PortNumber  = 60000;
const char *IPaddress = "192.168.100.200";
// const char *IPaddress = "192.168.100.165";
// const char *IPaddress = "192.168.1.5";


int gettimeofday();


float chg_deg(float lat)
{
    float deg;
    int deg_int;
    float minutes;
    float deg_min;

    deg_int = (int)lat/100;
    minutes = lat - (deg_int*100 );
    deg_min = deg_int + minutes/60.0;

//  printf("di:%d mi:%f dm:%f\n",deg_int,minutes,deg_min);

    return deg_min;
}

void arg_error()
{
    printf("Argment error!! type as below\n");
    printf("sudo ./hanki -d 0/1 -ip \"192.168.100.y -id 1\"\n");
    printf("-d 1 :show data  -d 0: no show data\n");
    printf("-ip \"192.168.100.y\": client PC ip address\n");
    printf("-id #: uniq RasPi ID <100\n");
    exit(0);
}

int main(int argc, char *argv[])
{
    unsigned char msg[] = "serial port open...\n";
    unsigned char cfn[DATA_SIZE_CMN]; // current file name based on size
    unsigned char buf[DATA_SIZE_CMN]   = {0};
    unsigned char buf_w[DATA_SIZE_CMN] = {0};
    unsigned char buf2[128] = {0};
    unsigned char ip_addr[32];
    int rd;
    int fd;
    struct termios tio;
    int baudRate = B9600;
    int datasave;
    double d_sec;
    int i;
    int j;
    int k;
    int l;
    int c;
    int tk;
    int item;
    int content;
    int cnt;
    int cng_file;
    int len;
    int len_w;
    int ret;
    int size;
    int disp;
    int store_hour;
    char header[16];
    char host_ip[32];
    float gpstime;
    float latitude;
    float latitude_deg;
    int latitude_deg_int;
    char nswe;
    float longitude;
    float longitude_deg;
    int longitude_deg_int;
    char eorw;
    int quality;
    int numgps;
    float lowrate;
    float avobesealevel;
    float hightg;
    int dgps;
    int base;
    int csum;
    int unit1, unit2, unit3, unit4, unit5, unit6;
    float true_c;
    float magnetic_c;
    float knot_sp;
    float kiro_sp;
    int mode;
    int msec;
    int sec;
    int nsec;
    int ps_msec;
    int d_sec_int;
    int display;
    int send_flag;
    int id;
    int msg_cnt = 0;
    time_t t;
    FILE *file;
    FILE *file_shm;
    struct tm *local;
    struct timespec start_time, end_time;
    struct tm *ptm;
    struct timeval tvToday;           //for msec
    float temp;
    int  id_wind;
    int  id_imu ;
    char *shmData_imu;
    char *shmData_wind;
    char data_wind[DATA_SIZE_WIND];
    char data_imu[DATA_SIZE_IMU];
    char data_udp[DATA_SIZE_UDP];

    struct sockaddr_in addr;
    int sock_df;
    int shmData_imu_flag  = TRUE;
    int shmData_wind_flag = TRUE;
    int arg_err_flg       = FALSE;

    char b_unit1[8];
    char b_unit2[8];
    char b_unit3[8];
    char b_unit4[8];

    if(argc == 7)
    {
        if(strcmp(argv[1],"-d") == 0)
        {
            if(strcmp(argv[2],"1") == 0) display = TRUE;
            else display = FALSE;
        }
        else
        {
            printf("sudo ./hanki -d 0/1 -ip \"192.168.x.y\" -id #\n");
            exit(0);
        }
        strcpy(host_ip,argv[5]);
        printf("%s:%s:%s:%s:%s:%s:%s\n",argv[0],argv[1],argv[2],argv[3],argv[4],argv[5],argv[6]);
    //  sscanf(argv[7],"%d",&id);
    }
    else
    {
        arg_error();
    }

// Check argv
    arg_err_flg = FALSE;
    for(i=0;i<argc;i++)
    {
        if (strcmp(argv[i],"-d")==0)
        {
            sscanf(argv[i+1],"%d",&display);
            if(display >1) arg_err_flg = TRUE;
        }
        else if(strcmp(argv[i],"-ip")==0)
        {
            strcpy(host_ip,argv[i+1]);
        }
        else if(strcmp(argv[i],"-id")==0)
        {
            sscanf(argv[i+1],"%d",&id);
            if(id>99) arg_err_flg = TRUE;
        }
        if(arg_err_flg == TRUE) arg_error();
    }

    printf("display:%d host_ip:%s id:%d\n",display,host_ip,id);

    /*   
       if(argc >1) display = TRUE;
       else display = FALSE;
    */
    sock_df = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock_df < 0)
    {
        perror("Couldn't make a socket");
        return -1;
    }
    // 通信の設宁E
    addr.sin_family      = AF_INET; //IPv4を指宁E
    addr.sin_port        = htons(PortNumber);
                                 //ポぅト番号。ここでは60000を指宁E
    addr.sin_addr.s_addr = inet_addr(host_ip); //サーバぅ側のアドレス
    ssize_t send_status;

    // Shared memory create a new with IPC_CREATE
    if((id_wind = shmget(IPC_PRIVATE, DATA_SIZE_WIND, IPC_CREAT|0666)) == -1)
    {
        perror("shmget()");
        return -1;
    }

     // Shared memory create a new with IPC_CREATE
    if((id_imu = shmget(IPC_PRIVATE, DATA_SIZE_IMU, IPC_CREAT|0666)) == -1)
    {
        perror("shmget()");
        return -1;
    }

    // Attach shared memory for IMU
    if((shmData_imu = (char *)shmat(id_imu, NULL, 0)) == (void *)-1)
    {
        printf(" imu shard memory error\n");
        perror("shmat()");
    }

    // Attach shared memory for WIND
    if((shmData_wind = (char *)shmat(id_wind, NULL, 0)) == (void *)-1)
    {
        printf(" wind shard memory error\n");
        perror("shmat()");
    }

    if(display == TRUE) printf("Shm ID_WIND:%d ID_IMU:%d\n",id_wind,id_imu);

    file_shm = fopen("shared_id.txt","w");
    fprintf(file_shm,"%d,%d",id_wind,id_imu);
    fclose(file_shm);

 //   while(1);

    fd = open(SERIAL_PORT, O_RDWR);
    if (fd < 0)
    {
        printf("serial 1 open error\n");
        return -1;
    }

    tio.c_cflag += CREAD;
    tio.c_cflag += CLOCAL;
    tio.c_cflag += CS8;
    tio.c_cflag += 0;
    tio.c_cflag += 0;

    cfsetispeed( &tio, baudRate );
    cfsetospeed( &tio, baudRate );

    cfmakeraw(&tio);

    tcsetattr( fd, TCSANOW, &tio );
    tcsetattr( rd, TCSANOW, &tio );

    ioctl(fd, TCSETS, &tio);
    ioctl(rd, TCSETS, &tio);

    cnt      = 0;
    cng_file = 1;
    shmData_imu_flag  = TRUE;
    shmData_wind_flag = TRUE;

    clock_gettime(CLOCK_MONOTONIC, &start_time);

    while(1)
    {
        clock_gettime(CLOCK_MONOTONIC, &start_time);

        if(cng_file == 1)                    // generate file name
        {
            t     = time(NULL);
            local = localtime(&t);
            sprintf(cfn,"/media/pi/NTSEL/HANKI/GPS/gps%02d%02d%02d%02d.txt",local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min);
            file       = fopen(cfn,"a");
            cng_file   = 0;
            store_hour = local->tm_hour;
//          printf("File create %s\n",cfn);
        }
        strcpy(buf,"");
        len = read(fd, buf, sizeof(buf));

//      printf("buf:%s\n",buf);

        //check header
        sscanf(buf,"%[^,]",header);
        if(strcmp("$GPGGA",header) == 0)
        {
//          printf("\rbuf1:%s\n",buf);
//          printf("header:%s\n",header);
            sscanf(buf,"%[^,],%f,%f,%c,%f,%c,%d,%d,%f,%f,%d,%f,%d,%d,%d,%d",
            header,&gpstime,&latitude,&nswe,&longitude,&eorw,&quality,&numgps,&lowrate,&avobesealevel,&unit1,&hightg,&unit2,&dgps,&base,&csum);
//          printf("header:%s gpstime:%f lat:%f lng:%f asl:%f\n",header,gpstime,latitude,longitude,avobesealevel);
            latitude_deg      = chg_deg(latitude);
            longitude_deg     = chg_deg(longitude);
            latitude_deg_int  = (int)latitude_deg;
            longitude_deg_int = (int)longitude_deg;

            if((latitude_deg_int > 37) || (latitude_deg_int < 32)) latitude_deg = 0;
            if((longitude_deg_int > 140) || (longitude_deg_int < 134)) longitude_deg = 0;
            send_flag = TRUE;
        }

        if(strcmp("$GPVTG",header) == 0)
        {
//          printf("\rbuf_VTG:%s\n",buf);
//          printf("\rheader:%s\n",header);
            c=0;
            for(i=0;i<50;i++)
            {
                buf2[c] = buf[i];
                if(buf[i]==',')
                {
                    if(buf[i+1] == ',')
                    {
                        buf2[c+1] = 0x30;
                        c++;
                    }
                }
                if(buf[i] =='*') break;
                c++;
            }
            buf2[c] = '\0';
//      printf("\r\nbus2:%s\n",buf2);

            sscanf(buf2,"%[^,],%f,%[^,],%f,%[^,],%f,%[^,],%f",header,&true_c,b_unit1,&magnetic_c,b_unit2,&knot_sp,b_unit3,&kiro_sp);
            //          printf("h:%s,t:%f,u:%s,m:%f,u:%s,k:%f,u%s,s:%f\n",header,true_c,b_unit1,magnetic_c,b_unit2,knot_sp,b_unit3,kiro_sp);
            /*          
                        sscanf(buf,"%[^,],%f,%c,%f,%c,%f,%c,%f,%c,%c,%x",
                        header,&true_c,&unit1,&magnetic_c,&unit2,&knot_sp,&unit3,&kiro_sp,&unit3,&mode,&csum);
                        if((true_c > 360) || (true_c < 0))true_c = 999.9;
                        printf("\rbuf_VTG:%s\n",buf);
                        printf("CHK_BUF: %s,%f,%c,%f,%c,%f,%c,%f,%c,%c,%x",
                        header,true_c,unit1,magnetic_c,unit2,knot_sp,unit3,&kiro_sp,unit3,mode,csum);
                        printf("\rVTG ->header:%s knot:%f speed:%f %x true_c:%f\n",header,knot_sp,kiro_sp,unit6,true_c);
            */
        }
        cnt++;
        t     = time(NULL);
        local = localtime(&t);
        ret   = gettimeofday(&tvToday,NULL); //Today
        ptm   = localtime(&tvToday.tv_sec);
//      printf("%02d/%02d %02d:%02d:%02d:%03d\n",ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec,tvToday.tv_usec/1000);
//      printf("%02d/%02d %02d:%02d:%02d\n",local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min,local->tm_sec);

        strcpy(buf_w,"");
        sprintf(buf_w,"ID:%02d,MCT:%06d,TIME:%02d/%02d,%02d:%02d:%02d:%03d LAT:%02.6f LNG:%02.6f QAL:%1d ASL:%05.1f SPD:%05.1f TRC:%05.1f",
        id,msg_cnt,
        ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec,tvToday.tv_usec/1000,latitude_deg,longitude_deg,quality,avobesealevel,kiro_sp,true_c);

        if(display == TRUE) printf("\n\rbuf_w > %s",buf_w);
        if(send_flag == TRUE)
        {
            fprintf(file,"%s",buf_w);
            send_flag = FALSE;
        }

        if(store_hour != local->tm_hour)
        {
            fclose(file);
            cng_file = 1;
            cnt      = 0;
        }

//check timer
        clock_gettime(CLOCK_MONOTONIC, &end_time);
        sec  = end_time.tv_sec - start_time.tv_sec;
        nsec = end_time.tv_nsec - start_time.tv_nsec;
        if(nsec < 0) nsec = 1000000-nsec;
        d_sec = (double)sec + (double)nsec / (1000 * 1000 * 1000);
        msec  = (int)(d_sec*1000);
//      printf("\n 1  d_sec:%f sec:%d msec:%d nsec:%d\n",d_sec,sec,msec,nsec);
        clock_gettime(CLOCK_MONOTONIC, &start_time);


// Shared memory convert char address for IMU

// update data_imu if IMU shared memory updated.
        if (strcmp(shmData_imu, data_imu) != 0)
        {
            if (strcmp(shmData_imu, data_imu) != 0)
            {
//              printf("%s\n\r", shmData_imu);
                strcpy(data_imu, shmData_imu);
            }
        }

// Shared memory convert char address for WIND
// update data_imu if WIND shared memory updated.
        if (strcmp(shmData_wind, data_wind) != 0)
        {
            if (strcmp(shmData_wind, data_wind) != 0)
            {
//              printf("%s\n\r", shmData_wind);
                strcpy(data_wind, shmData_wind);
            }
        }

//Transmite data to UDP server.
// buf_w,data_wind,data_imu
        sprintf(data_udp,"%s %s %s",buf_w,data_wind,data_imu);
        if(display == TRUE) printf("\n\rdata_udp:%s\n",data_udp);
// 送信
        send_status = sendto(sock_df, &data_udp , sizeof(data_udp) , 0,
                    (struct sockaddr *)&addr, sizeof(addr) );
        msg_cnt++;
        // 送信失敁E
        if(send_status < 0)
        {
            perror("send error");
            return -1;
        }
        /*       
               memset(data_wind,0,DATA_SIZE_WIND*sizeof(data_wind[0]));
               memset(data_imu,0,DATA_SIZE_IMU*sizeof(data_imu[0]));
               memset(shmData_wind,0,DATA_SIZE_WIND*sizeof(shmData_wind[0]));
               memset(shmData_imu,0,DATA_SIZE_IMU*sizeof(shmData_imu[0]));
        */
    }
    fclose(file);
    exit(0);
}

IMUのセンサーのプログラムです。IMUセンサーはメーカのドライバーやライブラリをインストールしてください。基本サンプルプログラムを使用しています。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include "../Sense_HAT_C_Pi/RaspberryPi/IMU/bcm2835/lib/IMU.h"

#define SERIAL_PORT "/dev/ttyACM0"
#define SERIAL_PORT2 "/dev/ttyUSB0"

#define TRUE 1
#define FALSE 0

#define NUM_MV_ROLL 10
#define NUM_MV_PITCH 10
#define NUM_MV_YAW 10
#define NUM_MV_ACEL_X 10
#define NUM_MV_ACEL_Y 10
#define NUM_MV_ACEL_Z 10
#define NUM_MV_CMMON 40
#define SAVE_INTERVAL 100 //msec
#define  ACCEL_COVERT 16384.0

IMU_ST_ANGLES_DATA stAngles;
IMU_ST_SENSOR_DATA stGyroRawData;
IMU_ST_SENSOR_DATA stAccelRawData;
IMU_ST_SENSOR_DATA stMagnRawData;

int gettimeofday();

int main(int argc, char *argv[])
{
    unsigned char msg[] = "serial port open...\n";
    unsigned char cfn[255];           // current file name based on size
    unsigned char buf[255] = {0};
    unsigned char buf_w[255] = {0};
    int fd;
    int rd;
    struct termios tio;
    int baudRate = B9600;
    int datasave;
    double d_sec;
    int i;
    int j;
    int k;
    int l;
    int tk;
    int item;
    int content;
    int cnt;
    int cng_file;
    int len;
    int len_w;
    int ret;
    int size;
    int disp;
    int store_hour;

    int cnt_mv_roll, cnt_mv_pitch, cnt_mv_yaw, cnt_mv_acel_x, cnt_mv_acel_y, cnt_mv_acel_z;
    float buf_roll[NUM_MV_CMMON], buf_pitch[NUM_MV_CMMON], buf_yaw[NUM_MV_CMMON];
    int buf_acel_x[NUM_MV_CMMON], buf_acel_y[NUM_MV_CMMON], buf_acel_z[NUM_MV_CMMON];
    float sum_roll, sum_pitch, sum_yaw;
    int sum_acel_x, sum_acel_y, sum_acel_z;
    float ave_roll, ave_pitch, ave_yaw;
    int ave_acel_x, ave_acel_y, ave_acel_z;
    int mode;
    int msec;
    int sec;
    int nsec;
    int ps_msec;
    int d_sec_int;
    int display;
    int id_wind;
    int id_imu;
    time_t t;
    FILE *file;
    FILE *file_shm;
    struct tm *ptm;
    struct timeval tvToday; //for msec
    struct tm *local;
    struct timespec start_time, end_time;
    float temp;

    IMU_ST_ANGLES_DATA stAngles;
    IMU_ST_SENSOR_DATA stGyroRawData;
    IMU_ST_SENSOR_DATA stAccelRawData;
    IMU_ST_SENSOR_DATA stMagnRawData;

    int   id;
    char  *shmData;

// GPSプロセスが書いた共有メモリのIDが書かれたファイルを読む。
    file_shm = fopen("shared_id.txt","r");
        if(file_shm == 0){
        printf("Can't open shared_id.txt\n");
        exit(0);
    }
    fscanf(file_shm,"%d,%d",&id_wind,&id_imu);

// IMUの初期化
    imuInit();

    cnt = 0;
    cng_file = 1;
    cnt_mv_roll = 0;
    cnt_mv_pitch = 0;
    cnt_mv_yaw = 0;
    cnt_mv_acel_x = 0;
    cnt_mv_acel_y = 0;
    cnt_mv_acel_z = 0;

// デバッグ用
    if(argc > 1) display = 1;
        else display = 0;
		
// 共有メモリにアタッチ		
    if((shmData = (char *)shmat(id_imu, 0, 0)) == (void *)-1) {
        perror("shmat()");
        exit(EXIT_FAILURE);
    }
		
    while(1) {
// 時間計測用の時計スタート
        clock_gettime(CLOCK_MONOTONIC, &start_time);

// USBにデータを書き込むためのファイル名の生成 一時間ごとに新しいファイルを作る。
        if(cng_file == 1){  // generate file name
            t = time(NULL);
            local = localtime(&t);
            sprintf(cfn,"/media/pi/USBNAME/imu%02d%02d%02d%02d.txt",local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min);
            file = fopen(cfn,"a");
            cng_file = 0;
            store_hour = local->tm_hour;
        }

// IMU のデータを取得
        imuDataGet( &stAngles, &stGyroRawData, &stAccelRawData, &stMagnRawData);
        usleep(50000);  // sleep for 50msec 50msec 周期で共有メモリにデータを書くため

// Check Timer 経過時間を知るために
        clock_gettime(CLOCK_MONOTONIC, &end_time);
        sec = end_time.tv_sec - start_time.tv_sec;
        nsec = end_time.tv_nsec - start_time.tv_nsec;
        if(nsec < 0) nsec = 1000000-nsec;
        d_sec = (double)sec + (double)nsec / (1000 * 1000 * 1000);
        msec = (int)(d_sec*1000);
//      printf("\n 1  d_sec:%f sec:%d msec:%d nsec:%d\n",d_sec,sec,msec,nsec);

        clock_gettime(CLOCK_MONOTONIC, &start_time);

// 移動平均の計算
        for(i=0;i<NUM_MV_CMMON-1;i++){
        sum_roll += buf_roll[i] = buf_roll[i+1];
        sum_pitch += buf_pitch[i] = buf_pitch[i+1];
        sum_yaw += buf_yaw[i] = buf_yaw[i+1];
        sum_acel_x += buf_acel_x[i] = buf_acel_x[i+1];
        sum_acel_y += buf_acel_y[i] = buf_acel_y[i+1];
        sum_acel_z += buf_acel_z[i] = buf_acel_z[i+1];
    }
        sum_roll += buf_roll[NUM_MV_CMMON-1] = stAngles.fRoll;
        sum_pitch += buf_pitch[NUM_MV_CMMON-1] = stAngles.fPitch;
        sum_yaw += buf_yaw[NUM_MV_CMMON-1] = stAngles.fYaw;
        sum_acel_x += buf_acel_x[NUM_MV_CMMON-1] = stAccelRawData.s16X;
        sum_acel_y += buf_acel_y[NUM_MV_CMMON-1] = stAccelRawData.s16Y;
        sum_acel_z += buf_acel_z[NUM_MV_CMMON-1] = stAccelRawData.s16Z;

        ave_roll = sum_roll/NUM_MV_CMMON;
        ave_pitch = sum_pitch/NUM_MV_CMMON;
        ave_yaw = sum_yaw/NUM_MV_CMMON;
        ave_acel_x = sum_acel_x/NUM_MV_CMMON;
        ave_acel_y = sum_acel_y/NUM_MV_CMMON;
        ave_acel_z = sum_acel_z/NUM_MV_CMMON;

        // Check Timer
//      clock_gettime(CLOCK_MONOTONIC, &start_time);
        clock_gettime(CLOCK_MONOTONIC, &end_time);
        sec = end_time.tv_sec - start_time.tv_sec;
        nsec = end_time.tv_nsec - start_time.tv_nsec;
        if(nsec < 0) nsec = 1000000-nsec;
        d_sec = (double)sec + (double)nsec / (1000 * 1000 * 1000);
        msec = (int)(d_sec*1000);
//      printf("\n 2 i:%d  d_sec:%f sec:%d msec:%d nsec:%d\n",i,d_sec,sec,msec,nsec);
        clock_gettime(CLOCK_MONOTONIC, &start_time);

// msec を計算するために
        ret = gettimeofday(&tvToday,NULL); //Today
        ptm = localtime(&tvToday.tv_sec);

        sum_roll  = 0;
        sum_pitch = 0;
        sum_yaw = 0;
        sum_acel_x  = 0;
        sum_acel_y  = 0;
        sum_acel_z  = 0;

// 共有メモリに書き込むデータの成型
        sprintf(buf,"AVR:%06.2f,AVP:%06.2f,AVW:%07.2f,AVX:%05.2f,AVY:%05.2f,AVZ:%05.2f,RWR:%06.2f,RWP:%06.2f,RWW:%07.2f,RWX:%05.2f,RWY:%05.2f,RWZ:%05.2f",
        ave_roll,ave_pitch,ave_yaw,ave_acel_x/ACCEL_COVERT, ave_acel_y/ACCEL_COVERT, ave_acel_z/ACCEL_COVERT,stAngles.fRoll, stAngles.fPitch, stAngles.fYaw,
        stAccelRawData.s16X/ACCEL_COVERT, stAccelRawData.s16Y/ACCEL_COVERT, stAccelRawData.s16Z/ACCEL_COVERT);

// USBのデータには時刻を付加
        sprintf(buf_w,"TIME:%02d/%02d-%02d:%02d:%02d:%03d %s\n",ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec,tvToday.tv_usec/1000,buf);
        if(display == TRUE) printf("%s",buf_w);
        fprintf(file,"%s",buf_w);
        cnt++;
        t = time(NULL);
        local = localtime(&t);
// 時間が一時間たったらファイルを更新
        if(store_hour != local->tm_hour) {
            fclose(file);
            cng_file = 1;
            cnt = 0;
        }

// 共有メモリにコピー
        strcpy(shmData, buf);
        if(display == TRUE) printf("IMU:%s\n", shmData);
      
         cnt++;
    }
    fclose(file);
    exit(0);
}

共有メモリのアタッチのループの中で何回も行うとメモリ食ってプロセスが死にます。なので、ここでは、一回だけアタッチするようにしてみました。毎回、デッタチすればループの中でも動くとは思います。

風速計です。RS422でNMEAでシリアルデータが来ます。今回はRS422-USB変換器を使用してUSBで取り込んでいます。直接RS422で取り込んだほうが安いかも。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define SERIAL_PORT "/dev/ttyACM0"
#define SERIAL_PORT2 "/dev/ttyUSB0"

#define TRUE 1
#define FALSE 0

#define SAVE_INTERVAL 100 //msec

int gettimeofday();

int main(int argc, char *argv[])
{
    unsigned char msg[] = "serial port open...\n";
    unsigned char cfn[255];           // current file name based on size
    unsigned char buf[255] = { 0 };
    unsigned char buf_w[255] = { 0 };
    unsigned char buf_shm[255] = { 0 };

 //   char lbuf[255] = {0};
    unsigned char DATA[20][11] = { 0, 0 };
    int fd;
    int rd;
    int len;
    struct termios tio;
    int baudRate = B38400;
    int datasave;
    double d_sec;
    int i;
    int cnt;
    int cnt1;
    int cng_file;
    int msec;
    int sec;
    int nsec;
    int ps_msec;
    int d_sec_int;
    int store_hour;
    int ret;
    int display = 1;
    int id_wind;
    int id_imu;
    time_t t;
    struct tm *ptm;
    struct timeval tvToday; //for msec
    FILE *file;
    FILE *file_shm;
    struct tm *local;
    char header[8];
    int deg;
    char ref;
    char unit;
    char status;
    float wind_speed;
    char csum[8];

    struct timespec start_time, end_time;
    float temp;

    char  *shmData;

    rd = open(SERIAL_PORT2, O_RDWR);
    if (rd < 0)
    {
        printf("serial 2 open error\n");
        return -1;
    }

    tio.c_cflag += CREAD;
    tio.c_cflag += CLOCAL;
    tio.c_cflag += CS8;
    tio.c_cflag += 0;
    tio.c_cflag += 0;

    cfsetispeed(&tio, baudRate);
    cfsetospeed(&tio, baudRate);

    cfmakeraw(&tio);

    tcsetattr(fd, TCSANOW, &tio);
    tcsetattr(rd, TCSANOW, &tio);

    ioctl(fd, TCSETS, &tio);
    ioctl(rd, TCSETS, &tio);

    cnt = 0;
    cnt1 = 0;
    cng_file = 1;

//  clock_gettime(CLOCK_MONOTONIC, &start_time);
    if (argc > 1) display = 1;
    else display = 0;

    file_shm = fopen("shared_id.txt", "r");
    if (file_shm == 0)
    {
        printf("Can't open shared_id.txt\n");
        exit(0);
    }
    fscanf(file_shm, "%d,%d", &id_wind, &id_imu);
    if (display == TRUE) printf("Shm ID_WIND:%d ID_IMU:%d\n", id_wind, id_imu);

    if ((shmData = (char *)shmat(id_wind, 0, 0)) == (void *)-1)
    {
        perror("shmat()");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        clock_gettime(CLOCK_MONOTONIC, &start_time);

        if (cng_file == 1)  // generate file name
        {
            t = time(NULL);
            local = localtime(&t);
            sprintf(cfn, "/media/pi/USBNAME/wind%02d%02d%02d%02d.txt", local->tm_mon+1, local->tm_mday, local->tm_hour, local->tm_min);
            file = fopen(cfn, "a");
            cng_file = 0;
            store_hour = local->tm_hour;
//          printf("File create %s\n",cfn);
        }
        strcpy(buf, "");
        len = read(rd, buf, sizeof(buf));
        sscanf(buf, "%[^,],%d,%c,%f,%c,%d,%s", header, °, &ref, &wind_speed, &unit, &csum);
//        printf("%s,%d,%c,%2.1f,%c\n",header,deg,ref,wind_speed,unit);
        sprintf(buf_shm, "WDG:%03d,WRF:%c,WSP:%04.1f", deg, ref, wind_speed);
        local = localtime(&t);
        ret = gettimeofday(&tvToday, NULL); //Today
        ptm = localtime(&tvToday.tv_sec);

 //       printf("%02d/%02d %02d:%02d:%02d:%03d\n",ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec,tvToday.tv_usec/1000);
 //       printf("%02d/%02d %02d:%02d:%02d\n",local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min,local->tm_sec);

        sprintf(buf_w, "%02d/%02d %02d:%02d:%02d:%03d %s", ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, tvToday.tv_usec/1000, buf);
        if (display == TRUE) printf("%s", buf_w);
        fprintf(file, "%s", buf_w);
        cnt++;
        t = time(NULL);
        local = localtime(&t);
        if (store_hour != local->tm_hour)
        {
            fclose(file);
          cng_file = 1;
            cnt = 0;
        }

        strcpy(shmData, buf_shm);
        if (display == TRUE) printf("WIND:%s\n", shmData);
    }
    fclose (file);
    exit(0);
}