Motion Capture System

February 29, 2008

Dear forum members,

I hope this is the right place for the following question?

A class mate and I are collaborating on a project for a visualization and prototyping class. We have little experience using an I/O board, and its quite possible that we are overlooking something quite obvious. Would you please take a moment to look over our proposal. Your foresight may help us avoid wasting precious time and money. Thanks!

Our goal is to create a wearable motion capture system. The system will consist of bend sensors for the ankle, knee and hip of both the right and left legs (6 sensors in all). A compass will record heading information. A pressure sensor in each shoe will signal when each step is taken. The whole system will be controlled by an Arduino Diecimila board. We would like to save data to a flash drive. For this we will be using the FTDI Viniculum chip.

The data will be interpreted in MaxScript (a scripting tool found within 3D Studio Max). We will transfer the angles taken from the flex sensors onto a constrained bone structure within 3D Studio Max. Our compass value will determine direction. This information will then be used to visualize a hike through our favorite trail. We realize that there are more exact ways of transcribing absolute position (i.e. GPS) but we are more interested in movement in relation to the body itself.

The parts we are planning to purchase are as follows?

[u]Main Board[/u]

1 Arduino USB board (diecimila) http://www.sparkfun.com/commerce/product_info.php?products_id=666

1 ftdi viniculum chip for writing to usb memory? Suggested here? http://www.arduino.cc/playground/Main/UsbMemory

http://apple.clickandbuild.com/cnb/shop/ftdichip?op=catalogue-products-null&prodCategoryID=53&title=VDIP1

[u]Sensors[/u]

1 Compass Compass Module - HMC6352 Suggested by a user here? http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1170973485

http://www.sparkfun.com/commerce/product_info.php?products_id=7915

2 Pressure sensors

Flexiforce Pressure Sensors for detecting when a step is taken?plus the Op-amp circuit for implementing the FSR sensor http://www.imagesco.com/sensors/force-sensors.html For the sensor and the circuit

6 Flex sensors Flex Sensor http://www.imagesco.com/sensors/flex-sensor.html

[u]Power Supply[/u]

We will also need a power supply, but that should be pretty straight forward.

Are we heading down the right path? Are we missing anything crucial from a hardware point of view? Any suggestions or insights would be appreciated.

Thanks!

Carlo and Don

sounds cool! you might consider the lilypad if you want to put everything in the wearable... sparkfun also sells a great SD memory break out board. see: http://www.sparkfun.com/commerce/product_info.php?products_id=8215 http://www.cs.colorado.edu/~buechley/LilyPad/extend.html

very interesting project.

One thing you should consider very carefully is how to interface each of your sensors. With out extra circutry you have 6 analog inputs and it seems that you are going to use them up for the flex sensores.

The two preassure sensors are analog sensores too and will need 2 analog inputs, so you need a way to expand the number of analog inputs onthe Arduino board. This is not very difficult, check the playground for how to use the 4051 analog multiplexor IC.

The compass uses 12C that should not be a problem.

The FTDI Viniculum chip can interface serially if my memory serves me.

I think the complexity in this project wil come from the many different ways you are going to interface to your sensors.

Mulitplexed analog input from flex and preassure sensors. I2C for the compass Serial for the FTDI

But i think it is possible.

So what you are missing is a way to use more than 6 analog inputs. A method is described in the playground here: http://www.arduino.cc/playground/Learning/4051

Good luck

Hey Guys (and/or Gals?),

Thanks for your input so far! Its great to know our project isn't too far fetched.

We checked out the LilyPad and comparing it side by side with the Diecimila, it seems like they both have the same number of I/O pins. The main differences seem to be that the LilyPad uses less power and has a slower clock speed. Is that it? The lilly pad also costs almost half the price of the Diecimila. It does look like it has a lot less components, and its lacking the long chip found on the Diecimila. Being able to sew it into clothing isn't that important to us at the moment. We'd certainly prefer expandability/flexibility over style for now. Can you confirm the difference between one and the other?

As for multiplexing, yah... we will definitely be needing some of that! Thanks for the suggestion and the link...

Carlo and Don

Hi Everyone,

We sort of dropped off the planet for a while but we are back. I got the Arduino starter kit the other day along with the flex sensors and Don and I finally had some time to look at it today. For any noobs out there, believe me when I say [u]you have nothing to worry about[/u]! We followed the directions (http://www.arduino.cc/en/Guide/Windows) and were up and running pretty quick. I still can't believe how well documented this site is!

We then hooked up a bend sensor. Now keep in mind, neither of us have much in the way of electronics backgrounds. Much of this was done on faith alone. I'm happy to report we managed to not create any smoke. In fact, in short time we were watching values alternate in our Processing window as we bent the sensor back and forth in real time. We even programmed it so that the led would turn on only when the bend sensor hit a particular range in angle.

The really exciting part was that even when we thought we were stuck, we just sort of intuitively felt our way through it (it really helps having two people in these times of doubt). I don't expect the rest of the project to go quite as smooth, and when it doesn't, I hope I remember these good times we've had!

As for the project in general, due to limits in time and money, we have decided to scale back. We will only be using 6 bend sensors (for each side of the body? 1 at the knee, 1 at the hip-frontal, 1 at the hip-lateral). This should give us enough data to interpolate movement within 3DS Max.

We also met with our scripting guru today and went over the requirements as far as the kind of file type required for Maxscript. I think that side is well covered.


Our biggest concern at the moment is where to store the information.

Ideally we want 60 samples per second for our sensors (although we can go down to 30 if we have to). This will give us enough data to produce fluid motion when the data is reconstructed. Each of these 60 samples will contain 6 integer values (coming off each flex sensor). If I understand correctly, each integer takes up 2 bytes, so

2*6 = 12 bytes / sample 12 bytes * 60 samples per second = 720 bytes / second This works out to 2.47 megs/hour

I would like to collect data for about an hour at a time.

I've searched the internet and these forums looking for well documented ways to store data with the Arduino. So far the two most accessible systems seem to be USB and DataFlash Memory?

USB (ftdi) http://www.arduino.cc/playground/Main/UsbMemory

DataFlash Memory http://www.arduino.cc/playground/Code/Dataflash

I'm tempted to go with USB because it is a more universal standard and I already have a thumb drive I can use.

The problem is that in the description of the ftdi board above, the author notes “If you write info to it too quickly then it could possibly lose info as it won't be able to pause the sending of info?”

Do you think our application (our transfer rates?) would cause the system to loose information? Would the DataFlash system be exempt from this caveat?

Also, given that we are really just starting out, is one system easier to implement from a programming perspective than the other?

Any suggestions on which way to go would be much appreciated.

Thanks!

Carlo and Don

I’ll try and post up the code for writing to an SD flash card in the next few days. Maybe that would suite your needs. Then you dont need to buy expensive chips and stuff and can just write to SD cards.

I'm tempted to go with USB because it is a more universal standard and I already have a thumb drive I can use.

Just so you know, FTDI chips only talk to computers over USB. Thumb drives dont work.

Dataflash is the easiest by a long shot. Just put on a button which transmits all the recorded data over USB when your done.

I'm tempted to go with USB because it is a more universal standard and I already have a thumb drive I can use.

Just so you know, FTDI chips only talk to computers over USB. Thumb drives dont work.

Not true. They also make a serial, SPI, or parallel to USB host controller chip, the VNC1L. http://www.vinculum.com/prd_vnc1l.html

Thanks for your feedback, everyone!

Having looked more closely at our options, I think we are going to avoid the USB system if for no other reason than that the potential loss of data seems like a limitation. USB is not meant for constant writing of data, as far as we can tell, and this is exactly what we want.

So it seems we will be going with a Flash system. But which one?

We looked at the DosONChip sold by sparkfun here? http://www.sparkfun.com/commerce/product_info.php?products_id=8215

But in speaking to someone in the know and in doing research on this forum, it seems there are many unhappy costumers with this product. Its documentation is severely limited and more importantly, it has an upload transfer limit of around 480 bytes per second (see here: http://forum.sparkfun.com/viewtopic.php?t=5065).

It looks like after all is said and done, we are going to go with an Atmel AT45DB642D (http://atmel.com/dyn/products/product_card.asp?part_id=3777). It isn't removable, but it will provide us with around 8 megabytes of storage which will give us room to grow. Also, I called the manufacturer today and they confirmed this chip will write 1024 bytes in 17 milliseconds, plenty for our needs. Hopefully the library provided here will work, as both products are from the same family: http://www.arduino.cc/playground/Code/Dataflash

Carlo and Don

We looked at the DosONChip sold by sparkfun here? http://www.sparkfun.com/commerce/product_info.php?products_id=8215 But in speaking to someone in the know and in doing research on this forum, it seems there are many unhappy costumers with this product.

I'm surprised sparkfun let people express their displeasure in the forum. There's a new "level1" in town, and he's cracking down on unhappy customers!

as far as i know, you can talk to sd/mmc cards over spi (synchronous serial)

i defiantly will be interested in seeing this complete :) i wouldn't mind having a go at something like this for myself if u are successful and don't mind sharing code and stuff :D i use 3ds max myself and it would be great to make my own motion capture stuff.

getting it to attach to a biped would probably be a great way to go for portability..

Hey peoples!!

Aren't you all having a good day?

We're not doing so good over here in project “motion capture system” world!

After purchasing the Atmel AT45DB642D, we realized it was pretty much unusable as its connections were too small to solder to.

So we went with the USB option?

http://www.vinculum.com/prd_vdrive1.html

We spoke with the technician at vinculum and he assured us the write speed should not be an issue. If anything the Arduino is where the system will bottleneck, as the USB device can write up to 3 million bauds (AFAICT the Arduino tops out at 9600 baud).

We adopted the code from the playground for use with the USB ftdi VDIP1 (thanks to Nick!). Both devices use the same host controller and use the same firmware.

After two days of constant code pounding, we're having some issues getting the ftdi, vdrive 2 to write.

So we're hoping some one can take a look at this and maybe advise us on what we've over looked. The following code is the full code for the project as it stands. You really can't test this unless you have a lot of miscellaneous parts laying around your workshop and considerable time. The project has 6 analog-in sensors, what should be obvious is that it starts reading the sensors and then saves them to a file when ever a digital button is on. As long as the button stays on it will keep reading and writing to a file using a loop (incremental numbers). When the button is turned off it resets the base variables so you can start over.

The problem we're having comes in several varieties (current posted code slightly changed). The first problem comes when we write just one value like 100 to the incremental files. In this case we can only write to a total of 17 files during that session, even though we are asking it to write many more times. After that it stops making new files? we have tried incrementing in all three ways we know with the ++ operator, the +='s operator and simply var = var + 1. All give the same issue? no more than 17 files are created. It's also worth noting that we are watching the serial commands in a terminal program, and visualy know that we have issued the commands for the unwritten files..

The second problem happens when we write the 6 analog values to the files. In this case we can only write (if we're lucky) one file, and the second file (such as f1.txt) is empty, and no other file are written, even if we let the program run for say 20 iterations. So we added a long delay to the loop (6 seconds), since this error seems similar to when we write info too fast (no delay). This is a great deal of time and the problem persists. Which implies it's something we're not thinking of.

So it's 2:30 am. and we can't think any more. We figured we'd send a call out for help. Here is the current code, its highly documented but don't take any random comments to seriously as its still in a WIP. Please note that some areas of the code are not being used at the moment and its not really post worthy code, but hell it's a WIP.

Please see next post...

int noOfChars=0;  //the number of degits per a saved line when writing to USB
long int valToWrite=0;  //the value which gets writen to USB
long int x=0;  //transfer variable for a loop control
long int count = 0;  //the number of "frames recorded" or files writen

int btnPin = 10;  //the input pin for the on/off record button
boolean buttonOn = false;  //initiate the button to be off

int L_L = 5;  //left hip lateral sensor
int L_D = 4;  //left hip dorsal sensor
int L_K = 2;  //left knee sensor
// right side
int R_L = 0;  //right hip lateral sensor
int R_D = 1;  //right hip dorsal sensor
int R_K = 3;  //right hip knee

// carier values
int L_LV = 0;  //the value of the left hip lateral sensor
int L_DV = 0;  //the value of the left hip dorsal sensor
int L_KV= 0;  //the value of the left knee sensor
int R_LV = 0;  //the value of the right hip lateral sensor
int R_DV = 0;  //the value of the right hip dorsal sensor
int R_KV = 0;  //the value of the right knee sensor

void setup() 
{ 
      Serial.begin(9600);                    // opens serial port, sets data rate to 9600 bps
        Serial.print("IPA");                  // sets the vdip to use ascii numbers (so I can read them in the code easily!)
        Serial.print(13, BYTE);               // return character to tell vdip its end of message
        //pinMode(13, OUTPUT);                  //return character
        
        pinMode(L_L, INPUT);                  //set the left lateral sensor to input
        pinMode(L_D, INPUT);                  //set the left dorsal sensor to input
        pinMode(L_K, INPUT);                  //set the left knee sensor to input
        pinMode(R_L, INPUT);                  //set the right lateral sensor to input
        pinMode(R_D, INPUT);                  //set the right dorsal sensor to input
        pinMode(R_K, INPUT);                  //set the right knee sensor to input
        
        pinMode(btnPin, INPUT);               //set the on/off record button to input
}
long int charsInVar(long int i)
{
  long int r = 1;
  long int temp;
  temp = i;
  while (temp >= 10)  //tanks to d mellis and nick for this bit
  {
  r++;
  temp/=10;
  }

return r;
}
void loop() 
{ 
    if(digitalRead(btnPin) == HIGH ) //if the button is on start "recording"
  {
// read the analog values ( 0 - 1023)
// our sensors non-bent values vary based on wire length but they seem to hover around 370 for short wires, to 400 and something for long wires
  
  // the left angle values
  L_LV = analogRead(L_L);
  L_DV = analogRead(L_D);
  L_KV = analogRead(L_K);
  // the right angle values
  R_LV = analogRead(R_L);
  R_DV = analogRead(R_D);
  R_KV = analogRead(R_K);
  //now that our angle values are in memory open a file and write them to the usb
  
  delay(6000);
//open a file
  Serial.print("OPW f");                  // open to write creates a file - named frame
  Serial.print(count);                  // add an incremental frame number to the record
  Serial.print(".TXT");                      // call the file a txt for ease of use
  Serial.print(13, BYTE);                    // return


//write too the file
 //valToWrite = valToWrite + 1;                       // the value we want to log
  //x=valToWrite;                       // need to copy valToWrite as getting no of characters will consume it
  noOfChars=6;                        //we are going todo 6 lines so we start with 6 return characters always, so we need calculate the amount to write for the sensor values

  noOfChars+=charsInVar(L_LV);        //add in each sensor value
  noOfChars+=charsInVar(L_DV);        //add in each sensor value
  noOfChars+=charsInVar(L_KV);        //add in each sensor value
  noOfChars+=charsInVar(R_LV);        //add in each sensor value
  noOfChars+=charsInVar(R_DV);        //add in each sensor value
  noOfChars+=charsInVar(R_KV);        //add in each sensor value
 //noOfChars +=1;                      //add 1 to the num as we will also write the return character

 Serial.print("WRF ");               //write to file (file needs to have been opened to write first)
 Serial.print(noOfChars);            //needs to then be told how many characters will be written
 Serial.print(13, BYTE);             //return to say command is finished

 Serial.print(L_LV);            //actually save the file 
 Serial.print(13, BYTE);         //write a return
 Serial.print(L_DV);            
 Serial.print(13, BYTE);
  Serial.print(L_KV);            
 Serial.print(13, BYTE);
  Serial.print(R_LV);            
 Serial.print(13, BYTE);
  Serial.print(R_DV);            
 Serial.print(13, BYTE);
  Serial.print(R_KV);            
 Serial.print(13, BYTE);


 //close file              
  Serial.print("CLF f");           // it closes the file
  Serial.print(count);                 // close the current frames count
  Serial.print(".TXT");                //txt was for ease of use latter on
  Serial.print(13, BYTE);             // return character
  count= count + 1;                            // increment the count to add a new file
  }
  else  //if the button is off, reset the file count, to make sure we have a fresh record every time the system is used
    count = 0;
    valToWrite=100;
}

Carlo and Don

I'm surprised sparkfun let people express their displeasure in the forum. There's a new "level1" in town, and he's cracking down on unhappy customers!

Actually, the fact that they allow people to express their displeasure on product reviews really impresses me about sparkfun. I might not buy those products, but I'm a lot more likely to buy from sparkfun because of it.

Just wondering... are you also monitoring the serial stream coming back for prompts and error messages from the device?

Edit:

P.S. I don't know how the serial communication works exactly, but the Arduino docs say that the incoming serial buffer is 128 bytes in size (http://www.arduino.cc/en/Serial/Available), so if your code isn't reading these bytes (as it appears it's not), maybe the buffer is filling up and setting CTS or whatever low so that the USB thingie can't send its prompts back, and things just lock up? I see from the Vinculum firmware docs that the device sends back a 5-character prompt for each command ("D:>" plus CR).

Maybe just try clearing out the buffer each time with:

if (Serial.available() > 0) { int i, j ; i = Serial.available() ; while (i--) j = Serial.read() ; }

Just a wild guess!

Jmknapp,

Thanks for your help!

You're logic seems sound. The Arduino has a relatively large read buffer (for now we're assuming the write buffer is shared) so we figure we did sit at around 40 characters with all of our commands per frame, but those should be getting cleared out pretty fast, so it would take a great deal of return processing to fill up that buffer. This was why we originally didn't think we would need to clear out the buffer in between loops. But having read your suggestion, it made sense to clear the buffer anyways just to be safe. Thanks again.

We think the Vdrive has its own buffer, and this is what is getting bogged down. While it might be capable of writing speeds up too 3 million baud, we don't think the host controller is capable of understanding commands at that speed. It is getting bogged down probably in some form of an internal buffer.

It seems like “opw” and “clf” commands make life difficult, so instead of writing many files we are now writing one file per a recording session. Also, we broke up the actual write process with delays. So we now have a good beat on what's going on, though we are still uncertain on where things bottle neck.

We've figured out that in order to write successfully, the size of the delays need to be adjusted in proportion to the run time of the app (or the Vdrive will stop writing).

We just had our first good write session. This version of the code ran for around 10 min's at 5 frames a second. This is still too slow for animation purposes, but its a start!

The code is cleaned up a bit and should work if someone was to dare this feat at home ;)

Please see the next post for the working code.

Thanks!

Carlo and Don

int noOfChars=0;        //the number of digits per a saved line when writing to USB
long int count = 1;     //the number of "frames recorded" or files writen
int x = 0;              //for when you really need an int.


boolean recording = false;  //initiate the button to be off

int btnPin = 10;  //the input pin for the on/off record button

int L_L = 5;  //left hip lateral sensor
int L_D = 4;  //left hip dorsal sensor
int L_K = 2;  //left knee sensor
// right side
int R_L = 0;  //right hip lateral sensor
int R_D = 1;  //right hip dorsal sensor
int R_K = 3;  //right hip knee

// carier values
int L_LV = 0;  //the value of the left hip lateral sensor
int L_DV = 0;  //the value of the left hip dorsal sensor
int L_KV= 0;  //the value of the left knee sensor
int R_LV = 0;  //the value of the right hip lateral sensor
int R_DV = 0;  //the value of the right hip dorsal sensor
int R_KV = 0;  //the value of the right knee sensor

void setup() 
{ 
      Serial.begin(9600);                    // opens serial port, sets data rate to 9600 bps
        Serial.print("IPA");                  // sets the vdip to use ascii numbers (so I can read them in the code easily!)
        Serial.print(13, BYTE);               // return character to tell vdip its end of message
        
        pinMode(L_L, INPUT);                  //set the left lateral sensor to input
        pinMode(L_D, INPUT);                  //set the left dorsal sensor to input
        pinMode(L_K, INPUT);                  //set the left knee sensor to input
        pinMode(R_L, INPUT);                  //set the right lateral sensor to input
        pinMode(R_D, INPUT);                  //set the right dorsal sensor to input
        pinMode(R_K, INPUT);                  //set the right knee sensor to input
        
        pinMode(btnPin, INPUT);               //set the on/off record button to input
}

//this function simplifies the calculation of characters for writing to the serial port.
long int charsInVar(long int i)
{
  long int r = 1;
  long int temp;
  temp = i;
  while (temp >= 10)  //tanks to d mellis and nick for this bit
  {
  r++;
  temp/=10;
  }

return r;
}
//  **MAIN LOOP**
void loop() 
{
  
if(digitalRead(btnPin) == HIGH ) //if the button is on do recording stuff
{
  //this little bit was recomended by jmknapp, to make sure that the buffer was emptied out each loop.. it seems to help a little bit. 
  if(x=Serial.available()>0)
  {
    while(x--)
    {
      Serial.read();
    }
  }
  
  if(!recording) //if the record btn is on, and we're not currently recording create a file to record in to.
  {
  //open a file
  Serial.print("OPW session");               // open to write creates a file
  Serial.print(count);                       // add an incremental number to the record
  Serial.print(".TXT");                      // call the file a txt for ease of use
  Serial.print(13, BYTE);                    // return
  recording = true;                          //set the record value to true so we don;t constantly create files
  delay(1000);                               //start after awhile to make sure we're not over powering the serial port durring a file creation(which seems to be easy to overpower)
  }
  //read and save the sensors!
  L_LV = analogRead(L_L);
  L_DV = analogRead(L_D);
  L_KV = analogRead(L_K);
  R_LV = analogRead(R_L);
  R_DV = analogRead(R_D);
  R_KV = analogRead(R_K);

  noOfChars=15;                        //we are always going todo 6 lines so we start with 6 return characters and six end-of-lines and then three more for our "sensor-set-break" character to register the frames with
  //add in each sensor value
  noOfChars+=charsInVar(L_LV);        
  noOfChars+=charsInVar(L_DV);        
  noOfChars+=charsInVar(L_KV);        
  noOfChars+=charsInVar(R_LV);        
  noOfChars+=charsInVar(R_DV);        
  noOfChars+=charsInVar(R_KV);        
  //doing writing stuff
 Serial.print("WRF ");               //write to file (file needs to have been opened to write first)
 Serial.print(noOfChars);            //needs to then be told how many characters will be written
 Serial.print(13, BYTE);             //return to say command is finished
   delay(25);  //these periodic delays radicly effect the amount of data you can save, with the vdrive before it stops working.
 Serial.println(L_LV);             
   delay(25);
 Serial.println(L_DV);
   delay(25);
 Serial.println(L_KV);             
   delay(25);
 Serial.println(R_LV);
   delay(25); 
 Serial.println(R_DV);
   delay(25); 
 Serial.println(R_KV);
   delay(25);
 Serial.println("b");
   delay(25);
    }
  else  //if the button is off, do some house cleaning
    {
      if(recording)//if the btn is off and we're still recording then close the file and increment the counter
      {
         //close file
        Serial.print("CLF session");           // it closes the file
        Serial.print(count)
Serial.print(".TXT");                //txt was for ease of use latter on
        Serial.print(13, BYTE);              // return character
        recording = false;                  //finally done recording.
        count++;                 // increment the count to add a new file
      }
    }
}

I can't see anything obviously wrong in the logic of the code.

I would run the sketch sending its serial down the wire to the pc and monitor what is actually being sent without involving the vdip.

This will help you work out if it is a bug in the code logic, or a mismatch in communication between the arduino and vdip.

If the code runs sending incremental file creation messages above what you get when connected then i would try connecting the vdip, and commenting out the value writing bit to see if i could create multiple files without writing data into them.

The writing with cts and rts connected to each other on the vdip is not how ftdi tell you to work, so it is proving unreliable - it could be that this is causing your problems.

I hope to look into it soon but don't have the time right now - there are other messages on the forum about this issue, and someone is grappling with it and may come up with working code sooner.

HTH

Nick

Sorry didn't see page 2!

Have posted some more info on this thread

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208060365/0#8