Trouble with Output from Spatial 1042

C, C++, and Visual C++
KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby KUWill » Fri Aug 29, 2014 9:27 am

Patrick, Frodegill, that was my fear when I realized that the Phidgets were sending the information on their own.

Patrick, I'd love to use the DataHandler, but it seems that I have no way of guaranteeing order when I write files. It would be GREAT if all the sensors were synchronized, but it seems the only way to do that is with polling. Is there a way to write the style to a CSV using the OnSpatialData_Handler? I'm using a PhidgetSBC3 and would be satisfied with +-1ms over the entire data range(a few minutes). Do you think the data will be accurate? Obviously we are logging from a mechanical system and the time response of the mechanical system is much slower than the standard 8ms that the Spatials do. Additionally, do you even think its worth going to "thread-locking" and other advanced concepts to achieve the previously stated accuracy? I'm a novice C++ programmer, obviously, but I am learning a ton from all this.

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Fri Aug 29, 2014 12:15 pm

KUWill wrote:It would be GREAT if all the sensors were synchronized

When you get used to Phidgets, you will understand how great it is that they are not. :wink:

KUWill wrote:Is there a way to write the style to a CSV using the OnSpatialData_Handler?

Of course. But you will probably have to do it Tetris-style, and that involves quite a bit of housekeeping..

Imagine an empty grid:

Code: Select all

t3 | - | - | - |
t2 | - | - | - |
t1 | - | - | - |


Then Spatial1 sends data (5) for tick1

Code: Select all

t3 | - | - | - |
t2 | - | - | - |
t1 | 5 | - | - |


..and Spatial3 sends data (7) for tick1

Code: Select all

t3 | - | - | - |
t2 | - | - | - |
t1 | 5 | - | 7 |


..and Spatial2 has collected two samples and sends data (3) for tick1 and data (4) for tick2

Code: Select all

t3 | - | - | - |
t2 | - | 4 | - |
t1 | 5 | 3 | 7 |


Anyone having played Tetris now rejoice, logs tick1, and removes the tick1 line

Code: Select all

Log:
t1;5;3;7

t4 | - | - | - |
t3 | - | - | - |
t2 | - | 4 | - |


Of course, real life always throws hurdles at you. Phidgets SpatialEventData timestamp has microsecond resolution (uint64 time = seconds*1000000L + microseconds), so you will not be able to do exact match on ticks but instead rely on some very small timespans. And you will also have to make up your mind on how you will handle not getting values for all devices for a given timespan, or getting multiple values for one device in a given timespan.
My tip: Find yourself a piece of paper, draw some grids, and play with values.


KUWill wrote:Additionally, do you even think its worth going to "thread-locking" and other advanced concepts to achieve the previously stated accuracy? I'm a novice C++ programmer, obviously, but I am learning a ton from all this.

With Phidgets, especially when you have multiple Phidgets attached, you should have a clear understanding of threads, locks and shared data. It is not difficult at all, but you need to think and be careful not creating deadlocks or miss some concurrent accesses. Feel free to ask, but I really think you should create this code yourself. As you say - you will learn a ton. And Phidgets make it all easy for you, even if it probably doesn't look like it right now :lol:

KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby KUWill » Fri Aug 29, 2014 2:42 pm

frodegill, that seems pretty complicated, but I'll give it a try some time.

I'm now having a compiler error. The compiler gives a fatal error "fstream.h" no such file or directory. Dare I ask how to fix this? The object oriented commands were much easier than using fprintf or other methods, but it seems as if I'm probably missing a whole host of library files...

FYI compiling on PhidgetSBC3.

KUWill
Phidgetsian
Posts: 7
Joined: Sun Aug 17, 2014 12:09 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby KUWill » Fri Aug 29, 2014 7:43 pm

Alright guys, I'm really hurting. Honestly, I just wanted to pull data from 3 Spatials and write them to three separate files with all their stamps. I get a segmentation fault when I try and run it, so I'm feeling pretty defeated. Please critique and advise how to resolve my issue. I just want to data log 3 Spatials with an SBC3, with their respective acceleration data and timestamps all at the same time. I don't care if it writes one file or three files any more. This is just way more complicated than I ever thought it would be. And here I thought compiling would be the limit of my problems...

Code: Select all

#include <stdio.h>
#include <phidget21.h>
#include <unistd.h>
#define DataLength 100000
using namespace std;

int charcount1;
int charcount2;
int charcount3;

struct FileInfo
{
   int filecounter;
   size_t filesize;
   int NameLength;
   FILE *fp;
};

struct Handles
{
   CPhidgetSpatialHandle spatial;
};

int CCONV SpatialDataHandler1(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
   int i;
   FILE *fp1 = (FILE *) userptr;
   for(i < 3; i++;)
   {
      fprintf(fp1, "%3f,", data[0]->acceleration[i]);
   }
   fprintf(fp1, "%4f,%6f,\n", data[0]->timestamp.seconds, data[0]->timestamp.microseconds);
}

int CCONV SpatialDataHandler2(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
   int i;
   FILE *fp2 = (FILE *) userptr;
   for(i < 3; i++;)
   {
      fprintf(fp2, "%3f,", data[0]->acceleration[i]);
   }
   fprintf(fp2, "%4f,%6f,\n", data[0]->timestamp.seconds, data[0]->timestamp.microseconds);
}

int CCONV SpatialDataHandler3(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
   int i;
   FILE *fp3 = (FILE *) userptr;
   for(i < 3; i++;)
   {
      fprintf(fp3, "%3f,", data[0]->acceleration[i]);
   }
   fprintf(fp3, "%4f,%6f,\n", data[0]->timestamp.seconds, data[0]->timestamp.microseconds);
}

int SpatialHandles(CPhidgetSpatialHandle spatial1, CPhidgetSpatialHandle spatial2, CPhidgetSpatialHandle spatial3)
{
   spatial1 = 0;
   spatial2 = 0;
   spatial3 = 0;
   
   CPhidgetSpatial_create(&spatial1);
   CPhidgetSpatial_create(&spatial2);
   CPhidgetSpatial_create(&spatial3);
   
   CPhidgetSpatial_setDataRate(spatial1, 8);
   CPhidgetSpatial_setDataRate(spatial2, 8);
   CPhidgetSpatial_setDataRate(spatial3, 8);
}

int FileOpen(int NameLength1, int NameLength2, int NameLength3, int counter1, int counter2, int counter3, FILE *filepointer1, FILE *filepointer2, FILE *filepointer3)
{
   char name1[15];
   char name2[15];
   char name3[15];
   
   NameLength1 = sprintf(name1,"Spatial1_%d",counter1);
   counter1++;
   NameLength2 = sprintf(name2,"Spatial2_%d",counter2);
   counter2++;
   NameLength3 = sprintf(name3,"Spatial3_%d",counter3);
   counter3++;
   
   filepointer1 = fopen(name1, "w");
   filepointer2 = fopen(name2, "w");
   filepointer3 = fopen(name3, "w");
}

int Logger(CPhidgetSpatialHandle spatial1, CPhidgetSpatialHandle spatial2, CPhidgetSpatialHandle spatial3, int CCount1, int CCount2, int CCount3, FILE* fp1, FILE* fp2, FILE* fp3)
{
   CPhidgetSpatial_set_OnSpatialData_Handler(spatial1, SpatialDataHandler1, (void*) fp1);
   CPhidgetSpatial_set_OnSpatialData_Handler(spatial2, SpatialDataHandler2, (void*) fp2);
   CPhidgetSpatial_set_OnSpatialData_Handler(spatial3, SpatialDataHandler3, (void*) fp3);

   CPhidget_open((CPhidgetHandle)spatial1, 296918);
   CPhidget_open((CPhidgetHandle)spatial2, 296927);
   CPhidget_open((CPhidgetHandle)spatial3, 296963);
   
   while (CCount1 < DataLength && CCount2 < DataLength && CCount3 < DataLength)
   {
      usleep(64);
      CCount1+(8*13);
      CCount2+(8*13);
      CCount3+(8*13);
   }
   
}

int FileClose(CPhidgetSpatialHandle spatial1, CPhidgetSpatialHandle spatial2, CPhidgetSpatialHandle spatial3, FILE *filepointer1, FILE *filepointer2, FILE *filepointer3)
{
   CPhidget_close((CPhidgetHandle)spatial1);
   CPhidget_close((CPhidgetHandle)spatial2);
   CPhidget_close((CPhidgetHandle)spatial3);
   
   fclose(filepointer1);
   fclose(filepointer2);
   fclose(filepointer3);
}

int main(int argc, char* argv[])
{
   FileInfo FileInfo1;
   FileInfo FileInfo2;
   FileInfo FileInfo3;
   Handles Handle1;
   Handles Handle2;
   Handles Handle3;
   SpatialHandles(Handle1.spatial, Handle2.spatial, Handle3.spatial);
   while( 0 == NULL)
   {
      FileOpen(FileInfo1.NameLength,FileInfo2.NameLength,FileInfo3.NameLength,FileInfo1.filecounter,FileInfo2.filecounter,FileInfo3.filecounter,FileInfo1.fp,FileInfo2.fp,FileInfo3.fp);
      Logger(Handle1.spatial,Handle2.spatial,Handle3.spatial,charcount1,charcount2,charcount3,FileInfo1.fp,FileInfo2.fp,FileInfo3.fp);
      FileClose(Handle1.spatial,Handle2.spatial,Handle3.spatial,FileInfo1.fp,FileInfo2.fp,FileInfo3.fp);
   }
}

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Sat Aug 30, 2014 1:15 am

KUWill wrote:I get a segmentation fault when I try and run it, so I'm feeling pretty defeated. Please critique and advise how to resolve my issue.

Once again, I am amazed you even got to comile this. If you are compiling using gcc/g++, please add -Wall -Werror when compiling. This instructs gcc to report all issues, and treat them as errors. It will frustrate you in the start, but you will end up with much more error-free and robust code.

I will do an honest code review below. Note that I will not go into details on your program flow, just show you what -Wall would have told you. Will also make some code, but I do not have time for that now.

Code: Select all

int CCONV SpatialDataHandler1(CPhidgetSpatialHandle spatial, void *userptr, CPhidgetSpatial_SpatialEventDataHandle *data, int count)
{
   int i;
   FILE *fp1 = (FILE *) userptr;
   for(i < 3; i++;)
   {
      fprintf(fp1, "%3f,", data[0]->acceleration[i]);
   }
   fprintf(fp1, "%4f,%6f,\n", data[0]->timestamp.seconds, data[0]->timestamp.microseconds);
}

1) You do not need 3 identical data handlers. This is what you use the CPhidgetSpatialHandle and user_ptr for (that is, create one handler that can handle all spatials).
2) Your for loops are totally wrong. "for" has 3 parameters. First is called before looping. Second is called before each iteration, and last is called after each iteration. Your loops is off-by-one here, and should give one big compiler warning. You probably meant "for (i=0; i<3; i++)"
3) fprintf %f expects parameters to be floats. You send two ints, so you should have used %d
4) You have a function said to return int, and no return statement. With phidgets, you normally return EPHIDGET_OK if everything went ok.
5) Minor issue: You do not use parameters spatial and count. Either use them, or tell compiler that you are fully aware of that you do not use them, either by commenting out the parameter
"CPhidgetSpatialHandle /*spatial*/"
or, easier to read:
"#define UNUSED(x)" and "CPhidgetSpatialHandle UNUSED(spatial)"

Code: Select all

int SpatialHandles(CPhidgetSpatialHandle spatial1, CPhidgetSpatialHandle spatial2, CPhidgetSpatialHandle spatial3)
{
   spatial1 = 0;
   spatial2 = 0;
   spatial3 = 0;
   
   CPhidgetSpatial_create(&spatial1);
   CPhidgetSpatial_create(&spatial2);
   CPhidgetSpatial_create(&spatial3);
   
   CPhidgetSpatial_setDataRate(spatial1, 8);
   CPhidgetSpatial_setDataRate(spatial2, 8);
   CPhidgetSpatial_setDataRate(spatial3, 8);
}

If your code looks like this, your brain should scream "Use arrays!".

Code: Select all

int FileOpen(int NameLength1, int NameLength2, int NameLength3, int counter1, int counter2, int counter3, FILE *filepointer1, FILE *filepointer2, FILE *filepointer3)
{
   char name1[15];
   char name2[15];
   char name3[15];
   
   NameLength1 = sprintf(name1,"Spatial1_%d",counter1);
   counter1++;
   NameLength2 = sprintf(name2,"Spatial2_%d",counter2);
   counter2++;
   NameLength3 = sprintf(name3,"Spatial3_%d",counter3);
   counter3++;
   
   filepointer1 = fopen(name1, "w");
   filepointer2 = fopen(name2, "w");
   filepointer3 = fopen(name3, "w");
}

I don't think you have complete understanding of calling by value versus calling by reference.
If you have a parameter "int NameLength1", it is called by value. You send a value in to a function, and whatever changes you do to it inside the function will be ignored when returning from the function.
If you have a parameter "int& NameLength1", it is called by reference. You send a pointer to a value in to the function, and whatever changes you do to it will remain when returning from the function.
You probably meant int& and FILE*& here. As it stands now, your function does nothing (except opening files and forget about opening them)

Code: Select all

int Logger(CPhidgetSpatialHandle spatial1, CPhidgetSpatialHandle spatial2, CPhidgetSpatialHandle spatial3, int CCount1, int CCount2, int CCount3, FILE* fp1, FILE* fp2, FILE* fp3)
{
   CPhidgetSpatial_set_OnSpatialData_Handler(spatial1, SpatialDataHandler1, (void*) fp1);
   CPhidgetSpatial_set_OnSpatialData_Handler(spatial2, SpatialDataHandler2, (void*) fp2);
   CPhidgetSpatial_set_OnSpatialData_Handler(spatial3, SpatialDataHandler3, (void*) fp3);

   CPhidget_open((CPhidgetHandle)spatial1, 296918);
   CPhidget_open((CPhidgetHandle)spatial2, 296927);
   CPhidget_open((CPhidgetHandle)spatial3, 296963);
   
   while (CCount1 < DataLength && CCount2 < DataLength && CCount3 < DataLength)
   {
      usleep(64);
      CCount1+(8*13);
      CCount2+(8*13);
      CCount3+(8*13);
   }
}

This one also creams "Arrays!", right?
And I'm not quite sure about your while loop. Right now it waits until either one of the CCounts exceed DataLength, but you never increment the CCounts. You do some arithmetics on the CCounts, but this is not stored anywhere. You probably meant CCount1+=(8*13); (that is, +=, not just +)

Code: Select all

int main(int argc, char* argv[])
{
   FileInfo FileInfo1;
   FileInfo FileInfo2;
   FileInfo FileInfo3;
   Handles Handle1;
   Handles Handle2;
   Handles Handle3;
   SpatialHandles(Handle1.spatial, Handle2.spatial, Handle3.spatial);
   while( 0 == NULL)
   {
      FileOpen(FileInfo1.NameLength,FileInfo2.NameLength,FileInfo3.NameLength,FileInfo1.filecounter,FileInfo2.filecounter,FileInfo3.filecounter,FileInfo1.fp,FileInfo2.fp,FileInfo3.fp);
      Logger(Handle1.spatial,Handle2.spatial,Handle3.spatial,charcount1,charcount2,charcount3,FileInfo1.fp,FileInfo2.fp,FileInfo3.fp);
      FileClose(Handle1.spatial,Handle2.spatial,Handle3.spatial,FileInfo1.fp,FileInfo2.fp,FileInfo3.fp);
   }
}

More unused parameters and more should-have-used-arrays. But this will probably fix itself when you fix the rest of the code.

As I said, I have not commented the program flow. I am not amazed your program does not log data, but by just listening to the compiler, I am certain you can make it log.

frodegill
Phidget Mastermind
Posts: 114
Joined: Thu Mar 04, 2010 2:51 am
Contact:

Re: Trouble with Output from Spatial 1042

Postby frodegill » Sat Aug 30, 2014 3:28 pm

frodegill wrote:Will also make some code, but I do not have time for that now.

..but here is some code!

I have deliberatly not added comments and I have deliberatly made some probably confusing constructions, but it compiles with -Wall -Werror, checks for errors, does not leak resources, and logs to files. Read the code, follow the flow, debug it, and try to understand each and every line. You have already learned a ton. Now you will learn two tons..

(Note that this one logs each spatial to a file of its own. There is thus no shared data and no need for mutexes)

Phidget guys: Why does the spatial have to be attached before calling CPhidgetSpatial_setDataRate?


Code: Select all

#include <cstdio>
#include "phidget21.h"

#define MAX_FILE_LENGTH (100000)


typedef struct
{
    int serial_no;
    CPhidgetSpatialHandle handle;
    FILE* file;
    int file_count;
    size_t file_length;

    CPhidgetHandle getHandle() const {return reinterpret_cast<CPhidgetHandle>(handle);}

    void createNewFile() {
                            char filename[100+1];
                            snprintf(filename, 100, "spatial_%d_%d.log", serial_no, ++file_count);
                            if (file)
                            {
                                fclose(file);
                            }
                            file_length = 0;
                            file = fopen(filename, "wb");
                         }
} SpatialInfo;


int CCONV SpatialDataHandler(CPhidgetSpatialHandle handle, void* userptr, CPhidgetSpatial_SpatialEventDataHandle* data, int count)
{
    SpatialInfo* spatial_info = reinterpret_cast<SpatialInfo*>(userptr);
    if (handle != spatial_info->handle)
        return EPHIDGET_UNEXPECTED;
   
    int axis_count;
    CPhidgetSpatial_getAccelerationAxisCount(spatial_info->handle, &axis_count);

    int i, j;
    for (i=0; i<count; i++)
    {
        spatial_info->file_length += fprintf(spatial_info->file, "%4d.%06d", data[i]->timestamp.seconds, data[i]->timestamp.microseconds);
        for (j=0; j<axis_count; j++)
        {
            spatial_info->file_length += fprintf(spatial_info->file, ";%0.3f", data[i]->acceleration[j]);
        }
        spatial_info->file_length += fprintf(spatial_info->file, "\n");

        if (MAX_FILE_LENGTH < spatial_info->file_length)
        {
            spatial_info->createNewFile();
        }
    }
    return EPHIDGET_OK;
}

bool RegisterSpatial(SpatialInfo& spatial_info, int serial_no)
{
    const char* err;
    int result;
    spatial_info.serial_no = serial_no;
    spatial_info.handle = NULL;
    if (EPHIDGET_OK!=(result=CPhidgetSpatial_create(&spatial_info.handle)))
    {
        CPhidget_getErrorDescription(result, &err);
        fprintf(stderr, "Failed to create spatial with serial number %d: %s\n", serial_no, err);
        return false;
    }

    spatial_info.file = NULL;
    spatial_info.file_count = 0;
    spatial_info.file_length = 0;
    spatial_info.createNewFile();

    if (EPHIDGET_OK!=(result=CPhidgetSpatial_set_OnSpatialData_Handler(spatial_info.handle, SpatialDataHandler, reinterpret_cast<void*>(&spatial_info))))
    {
        CPhidget_getErrorDescription(result, &err);
        fprintf(stderr, "Failed to set data handler for spatial with serial number %d: %s\n", serial_no, err);
        return false;
    }
    if (EPHIDGET_OK!=(result=CPhidget_open(spatial_info.getHandle(), serial_no)))
    {
        CPhidget_getErrorDescription(result, &err);
        fprintf(stderr, "Failed to open spatial with serial number %d: %s\n", serial_no, err);
        return false;
    }
    if (EPHIDGET_OK!=(result=CPhidget_waitForAttachment(spatial_info.getHandle(), 1000)))
    {
        CPhidget_getErrorDescription(result, &err);
        fprintf(stderr, "Failed to wait for attachment for spatial with serial number %d: %s\n", serial_no, err);
        return false;
    }
    if (EPHIDGET_OK!=(result=CPhidgetSpatial_setDataRate(spatial_info.handle, 8)))
    {
        CPhidget_getErrorDescription(result, &err);
        fprintf(stderr, "Failed to set data rate for spatial with serial number %d: %s\n", serial_no, err);
        return false;
    }
    return true;
}

void UnregisterSpatial(const SpatialInfo& spatial_info)
{
    CPhidget_close(spatial_info.getHandle());
    CPhidget_delete(spatial_info.getHandle());

    if (spatial_info.file)
        fclose(spatial_info.file);
}

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        fprintf(stderr, "Usage: %s <PhidgetSpatial serial no> [<PhidgetSpatial serial no>]...\n\n", argv[0]);
    }
   
    SpatialInfo* spatials = new SpatialInfo[argc-1];
   
    int spatial_count = 0;
    int i;
    for (i=1; i<argc; i++)
    {
        int serial_no;
        if (0 < sscanf(argv[i], "%d", &serial_no))
        {
            if (RegisterSpatial(spatials[spatial_count], serial_no))
            {
                spatial_count++;
            }
        }
    }

    if (0 < spatial_count)
    {
        fprintf(stdout, "Press [Enter] to end");
        getchar();
    }
   
    for (i=0; i<spatial_count; i++)
    {
        UnregisterSpatial(spatials[i]);
    }
    delete[] spatials;

    return 0;
}

User avatar
Patrick
Lead Developer
Posts: 3046
Joined: Mon Jun 20, 2005 8:46 am
Location: Canada
Contact:

Re: Trouble with Output from Spatial 1042

Postby Patrick » Tue Sep 02, 2014 9:25 am

frodegill wrote:Phidget guys: Why does the spatial have to be attached before calling CPhidgetSpatial_setDataRate?


Because the valid data rate range depends on which type of PhidgetSpatial is attached.

-Patrick


Return to “C/C++”

Who is online

Users browsing this forum: No registered users and 0 guests