#makewithmaxim VR glove

Published by jebrad042 in the blog jebrad042's blog. Views: 630


Introduction
This project initially sought out to create a VR data glove using the MAX32630 mbed controller to collect inertial, position, and finger information postion information and send that information via bluetooth. The TI CC2564 bluetooth chipset required a bluetooth stack to operate and that stack was available for purchase from TI's website. I did not wish to purchase the bluetooth stack and am currently investigating implementing the HCI messages over the UART.

BOM
Qty: 4 flex sensors from sparkfun - SEN-08606, 4.5" long conductive ink sensors for finger flex position sensing ($12.95 ea)
Qty: 1 flex sensor from sparkfun - SEN-10264, 2.2" long conductive ink sensors for thumb flex position sensing ($7.95 ea)
Qty 1: MCP3208 8-channel 12-bit SPI ADC for reading the 5 finger position sensors ($3.58 ea)

Schematics


Instructions
The first step in building the VR glove was to prototype the flex sensors for measuring finger flex position. I decided to use the same conductive ink sensors that were used on the Nintendo power glove. These sensors are variable resistive elements and could be easily interfaced with an ADC in a simple voltage divider circuit. An ADC with 10-bit or better resolution would provide plenty of resolution for this application. After purchasing several flex sensors from Sparkfun, I soldered .1" spacing dual male headers on the fragile contacts of the flex sensors so they could be inserted into a breadboard for prototyping. The MAX32630 development board has 4 ADC pin available, but I needed 5 for the flex sensors and thought that even more could potentially come in handy for other functions during the development stage, such as a variable delay between samples, SONAR or other positional sensors, etc. I decided to use the MCP3208, and 8 channel SPI 12-bit ADC from microchip because I already had some SPI code I used with a Rabbit 3000 Microprocessor. It was a very easy port from the C code to the mbed compiler. One minor problem I discover was that I accidentally mapped the SPI slave pins to the SPI bus (not the master pins) and could not get the program to run, although I don't believe a compiler error occurred. I double checked the pinout and realized that the SPI bus had different pin designations depending on what SPI functionallity you were intending.

pic_maxtest.jpg
Above is the breadboard prototype.



Correct SPI pins.PNG

I simply renamed the SPI functions from the Rabbit C compiler to match the mbed SPI API to spi.transfer() and get the external ADC up and running reading the finger positions as a RAW integer value.

FingerBend.PNG

Video
Let's see your project in action! Paste the YouTube link here and it will automatically be embedded.

Source Code
Code (Text):
  1.  
  2. #include "mbed.h"
  3. #include "max32630fthr.h"
  4. #include "USBSerial.h"
  5. #include "bmi160.h"
  6. #include "USBMSD_SD.h"
  7.  
  8. #define         RED "\[\033[0;31m\]"
  9. #define   LIGHT_RED "\[\033[1;31m\]"
  10. #define       GREEN "\[\033[0;32m\]"
  11. #define LIGHT_GREEN "\[\033[1;32m\]"
  12. #define        BLUE "\[\033[0;34m\]"
  13. #define  LIGHT_BLUE "\[\033[1;34m\]"
  14. #define      YELLOW "\[\033[1;33m\]"
  15. #define       WHITE "\[\033[1;37m\]"
  16. #define  LIGHT_GRAY "\[\033[0;37m\]"
  17.  
  18. MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
  19.  
  20. USBMSD_SD sd(P0_5, P0_6, P0_4, P0_7);  // mosi, miso, sclk, cs
  21.  
  22. // Hardware serial port over DAPLink
  23. Serial daplink(P2_1, P2_0);
  24. SPI spi(P5_1, P5_2, P5_0); // mosi, miso, sclk
  25. DigitalOut cs(P4_0);
  26.  
  27. // Virtual serial port over USB
  28. //USBSerial microUSB;
  29.  
  30. DigitalOut rLED(LED1);
  31. DigitalOut gLED(LED2);
  32. DigitalOut bLED(LED3);
  33. AnalogIn adc1(AIN_2);       //1.8 volt input
  34. //DigitalOut out1(P5_0);      //Digital output test
  35.  
  36. //Init bluetooth stuff
  37. Serial pan1326b(P0_1, P0_0);  
  38. DigitalOut pan1326b_CTS(P0_2);
  39. DigitalIn pan1326b_RTS(P0_3);
  40. DigitalOut pan1326b_RST(P1_6);
  41. DigitalOut pan1326b_CLK(P1_7);
  42.  
  43. //prototypes  
  44. void dumpImuRegisters(BMI160 &imu);
  45. void printRegister(BMI160 &imu, BMI160::Registers reg);
  46. void printBlock(BMI160 &imu, BMI160::Registers startReg, BMI160::Registers stopReg);
  47. int Get_MCP3208(int chan);
  48. void get_fingers(int *thumb, int *index, int *middle, int *ring, int *pinky);
  49. void Init_CC2564(void)
  50.  
  51. //------------- Functions ----------------------------------
  52. //See 6.4.2 Host Controller Interface for CC256X Dual Mode Bluetooth Controller
  53. void Init_CC2564(void){
  54.     pan1326b.baud(115200);
  55.  
  56. }
  57.  
  58. void CC2564_send_msg(char *str){
  59.     if(pan1326b_RTS == 0){
  60.      
  61.     }
  62.     else{
  63.         daplink.printf("RTS was high, terminate sending message\r\n");
  64.     }
  65. }
  66.  
  67. void get_fingers(int *thumb, int *index, int *middle, int *ring, int *pinky){
  68.     *thumb = Get_MCP3208(1);
  69.     *index = Get_MCP3208(2);
  70.     *middle = Get_MCP3208(3);
  71.     *ring = Get_MCP3208(4);
  72.     *pinky = Get_MCP3208(5);  
  73. }
  74.  
  75. int Get_MCP3208(int chan)
  76. {
  77.     unsigned char ch_result[3];
  78.     char cword[3];
  79.     typedef union
  80.     {
  81.         int intd;
  82.         char bytes[4];
  83.     }A2D_result;
  84.  
  85.     A2D_result A2D_result_1;
  86.  
  87.     cword[0] = 0x06; //Start bit, single
  88.     cword[0] += (chan >> 2);    // + MSB of chan
  89.     cword[0] &= 0x07;
  90.     cword[1] = (chan << 6); //2 LSB's of chan
  91.  
  92.     cs=0;
  93.  
  94.     ch_result[0] = spi.write(cword[0]);
  95.     ch_result[1] = spi.write(cword[1]);
  96.     ch_result[2] = spi.write(cword[2]);
  97.  
  98.     cs=1;
  99.  
  100.     ch_result[1] &= 0x0f;
  101.     A2D_result_1.bytes[1] = ch_result[1];
  102.     A2D_result_1.bytes[0] = ch_result[2];
  103.     A2D_result_1.bytes[2] = 0;
  104.     A2D_result_1.bytes[3] = 0;
  105.     return A2D_result_1.intd;
  106. }
  107.  
  108. // main() runs in its own thread in the OS
  109. // (note the calls to Thread::wait below for delays)
  110. int main()
  111. {
  112.     int c;
  113.  
  114.     wait(.2);
  115.     spi.format(8, 0);
  116.     spi.frequency(1000000);
  117.     daplink.baud(115200);
  118.     //daplink.printf("%s",WHITE); //Turn cursor white
  119.     daplink.printf("%s\r",LIGHT_GRAY); //Turn cursor light grey
  120.     daplink.printf("daplink serial port\r\n");
  121. //    microUSB.printf("micro USB serial port\r\n");
  122.     rLED = LED_ON;
  123.     gLED = LED_ON;
  124.     bLED = LED_OFF;
  125.  
  126.     rLED = LED_OFF;
  127.  
  128.     I2C i2cBus(P5_7, P6_0);
  129.     i2cBus.frequency(400000);
  130.     BMI160_I2C imu(i2cBus, BMI160_I2C::I2C_ADRS_SDO_LO);
  131.      
  132.     //--------------------------
  133.  
  134.     while(1) {
  135.         daplink.printf("\033[H");  //home
  136.         daplink.printf("\033[0J");  //erase from cursor to end of screen
  137.      
  138.         uint32_t failures = 0;
  139.      
  140.         if(imu.setSensorPowerMode(BMI160::GYRO, BMI160::NORMAL) != BMI160::RTN_NO_ERROR)
  141.         {
  142.             daplink.printf("Failed to set gyroscope power mode\r\n");
  143.             failures++;
  144.         }
  145.         wait_ms(100);
  146.      
  147.         if(imu.setSensorPowerMode(BMI160::ACC, BMI160::NORMAL) != BMI160::RTN_NO_ERROR)
  148.         {
  149.             daplink.printf("Failed to set accelerometer power mode\r\n");
  150.             failures++;
  151.         }
  152.         wait_ms(100);
  153.      
  154.      
  155.         BMI160::AccConfig accConfig;
  156.         //example of using getSensorConfig
  157.         if(imu.getSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
  158.         {
  159.             daplink.printf("ACC Range = %d\n", accConfig.range);
  160.             daplink.printf("ACC UnderSampling = %d\r\n", accConfig.us);
  161.             daplink.printf("ACC BandWidthParam = %d\r\n", accConfig.bwp);
  162.             daplink.printf("ACC OutputDataRate = %d\r\n\n", accConfig.odr);
  163.         }
  164.         else
  165.         {
  166.             daplink.printf("Failed to get accelerometer configuration\n");
  167.             failures++;
  168.         }
  169.      
  170.         //example of setting user defined configuration
  171.         accConfig.range = BMI160::SENS_4G;
  172.         accConfig.us = BMI160::ACC_US_OFF;
  173.         accConfig.bwp = BMI160::ACC_BWP_2;
  174.         accConfig.odr = BMI160::ACC_ODR_8;
  175.         if(imu.setSensorConfig(accConfig) == BMI160::RTN_NO_ERROR)
  176.         {
  177.             daplink.printf("ACC Range = %d\n", accConfig.range);
  178.             daplink.printf("ACC UnderSampling = %d\r\n", accConfig.us);
  179.             daplink.printf("ACC BandWidthParam = %d\r\n", accConfig.bwp);
  180.             daplink.printf("ACC OutputDataRate = %d\r\n\n", accConfig.odr);
  181.         }
  182.         else
  183.         {
  184.             daplink.printf("Failed to set accelerometer configuration\n");
  185.             failures++;
  186.         }
  187.      
  188.         BMI160::GyroConfig gyroConfig;
  189.         if(imu.getSensorConfig(gyroConfig) == BMI160::RTN_NO_ERROR)
  190.         {
  191.             daplink.printf("GYRO Range = %d\r\n", gyroConfig.range);
  192.             daplink.printf("GYRO BandWidthParam = %d\r\n", gyroConfig.bwp);
  193.             daplink.printf("GYRO OutputDataRate = %d\r\n\n", gyroConfig.odr);
  194.         }
  195.         else
  196.         {
  197.             daplink.printf("Failed to get gyroscope configuration\r\n");
  198.             failures++;
  199.         }
  200.      
  201.         wait(1.0);
  202.         printf("\033[H");  //home
  203.         printf("\033[0J");  //erase from cursor to end of screen
  204.      
  205.         if(failures == 0)
  206.         {
  207.             float imuTemperature;
  208.             BMI160::SensorData accData;
  209.             BMI160::SensorData gyroData;
  210.             BMI160::SensorTime sensorTime;
  211.          
  212.             while(1)
  213.             {
  214.                 unsigned int val;
  215.                 //val = Get_MCP3208(0);
  216.                              
  217.                 imu.getGyroAccXYZandSensorTime(accData, gyroData, sensorTime, accConfig.range, gyroConfig.range);
  218.                 imu.getTemperature(&imuTemperature);
  219.              
  220.                 daplink.printf("\033[H");  //home
  221.              
  222.                 daplink.printf("%s\r",RED); //Turn cursor red
  223.                 daplink.printf("ACC xAxis = %s%4.3f\r\n", "\033[K", accData.xAxis.scaled);
  224.                 daplink.printf("ACC yAxis = %s%4.3f\r\n", "\033[K", accData.yAxis.scaled);
  225.                 daplink.printf("ACC zAxis = %s%4.3f\r\n\n", "\033[K", accData.zAxis.scaled);
  226.              
  227.                 daplink.printf("%s\r",BLUE); //Turn cursor blue
  228.                 daplink.printf("GYRO xAxis = %s%5.1f\r\n","\033[K", gyroData.xAxis.scaled);
  229.                 daplink.printf("GYRO yAxis = %s%5.1f\r\n", "\033[K", gyroData.yAxis.scaled);
  230.                 daplink.printf("GYRO zAxis = %s%5.1f\r\n\n", "\033[K", gyroData.zAxis.scaled);
  231.                              
  232.                 daplink.printf("%s\r",GREEN); //Turn cursor green
  233.                 daplink.printf("Sensor Time = %s%f\r\n", "\033[K", sensorTime.seconds);
  234.                 daplink.printf("Sensor Temperature = %s%5.3f\r\n", "\033[K", imuTemperature);
  235.                          
  236.                 float ad_val = adc1.read();
  237.              
  238.                 daplink.printf("%s\r",LIGHT_GRAY); //Turn cursor light grey
  239.                 daplink.printf("ADC = %s%5.3f\r\n", "\033[K", ad_val);
  240.                 daplink.printf("\033[0J");  //erase from cursor to end of screen              
  241.              
  242.                 daplink.printf("%s\r",YELLOW); //Turn cursor yellow
  243.                 int thumb, index, middle, ring, pinky;
  244.                 get_fingers(&thumb, &index, &middle, &ring, &pinky);
  245.                 daplink.printf("%d,%d,%d,%d,%d\r\n", thumb,index,middle,ring,pinky);
  246.              
  247.                 gLED = !gLED;
  248.             }
  249.         }
  250.         else
  251.         {
  252.             while(1)
  253.             {
  254.                 rLED = !rLED;
  255.                 wait(0.25);
  256.             }
  257.         }
  258.     }
  259. }
  260.  
  261.  
  262.  
CAD Files
Attach or link to any CAD files if relevant to your project.
You need to be logged in to comment