pySerial revisited. Some Jason Mraz would be appreciated.

[ newline ] [ Arduino begin: parity ]

[ pySerial API ]

[ eLinux serial ] [ struct unpack ]

[ embeddedrelated ]

Intermittent failures. This is a screenshot of the txt file when things do seem to work.

Most of today went on fixing the serial communication. Earlier, I was trying to use pySerial’s readline(), and was changing the last two bytes of the packet to get \r and \n. Then, I come across one answer on stack exchange encouraging using read() instead.

That didn’t work out for quite a while, possibly because I wasn’t thoroughly updating Arduino’s firmware.

Anyway, it seems to work now (most of the time). Turns out that I can change the parity, stop bits, and number of bits in a byte for serial – but the default configuration works.

The main culprit, besides correcting the firmware, was probably not waiting for the serial buffer (4096 bytes?) to be filled. Sleep, being so good as it is, seems to fix that.



import serial
import time
from time import gmtime, strftime
import datetime

ser = serial.Serial(
    port='/dev/ttyACM0',
    baudrate=57600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
    )

f = open('dataFile.txt','w')
f.write(strftime("%Y-%m-%d %H:%M:%S", gmtime())+'\n')

l = ['p', 'l', 'e', 'a', 's', 'e', ' ', 'w', 'o', 'r', 'k']

i = 0
while(i<10):
    time.sleep(1) #for filling up the buffer?
    if ser.inWaiting():
        data = ser.read(ser.inWaiting())
        f.write(data)
    #else: reset Uno...
    #    print("waiting\n")
    #print struct.unpack('BBBBBBBBBBBBBBBB', data)
    
    print i
    #print l[i]
    i = i+1

f.close()
ser.close()
/////////////////////////////////////////////
// Team UMAR-VARS                          //
// Arduino code for grabbing               //
// - ECG/EMG data (A0, A1)                 //
// - PPG data     (A2)                     //
// - acc data     (A5, A6) - I2C - raw     //
////////////////////////////////////////////////////////////////////////////////////////////
// Links:
// - User manual
// https://www.olimex.com/Products/Duino/Shields/SHIELD-EKG-EMG/resources/SHIELD-EKG-EMG.pdf
// - ECG code from Stan12's code (which is adapted from Olimex's sample code)
// https://www.olimex.com/forum/index.php?topic=572.0
// - MPU-6050 code from JohnChi's example sketch
////////////////////////////////////////////*BEGIN*/////////////////////////////////////////

  #include<FlexiTimer2.h>  //http://playground.arduino.cc/Main/FlexiTimer2 for interrupts (timing)
  //#include <compat/deprecated.h> //seems to be outdated
  #include<Wire.h>                 //for I2C

  // MPU-6050:
      const int MPU=0x68;  // I2C address of the MPU-6050. Max 7 bits.
      //int16_t AcX,AcY,AcZ; //,Tmp,GyX,GyY,GyZ;  
  // ECG shield:
      volatile unsigned char CurrentCh = 0;       // Current channel being sampled.
      volatile unsigned int  ADC_Value = 0;	  // ADC current value, 2 byte value (16 bits total)
      volatile unsigned char TXBuf[2+1+2*3+2*3];  // sync + packetNum + heartData + accData
      volatile unsigned char TXIndex;             // Next byte to write in the transmission packet.

  void setup() {
      //pinMode(13, OUTPUT);
      
  // MPU-6050:   
      //do NOT place noInterrupts() here. Seems to affect I2C?
      Wire.begin();                               // as master
      Wire.beginTransmission(MPU);                // "queue bytes for transmission with write(), transmit by calling endTransmission()"
      Wire.write(0x6B);  // PWR_MGMT_1 register
      Wire.write(0);     // set to zero (wakes up the MPU-6050)
      Wire.endTransmission(true);
      
  // ECG shield:
      noInterrupts();  // Disable all interrupts before initialization
   
      //Packet | units?
      TXBuf[0] = 0xa5;    //Sync 0 -- could help with parsing -- unchanged for legacy
      TXBuf[1] = 0xa5;
      TXBuf[2] = 0x0;     //Packet counter -- helps to see what we might miss
      TXBuf[3] = 0x02;    //ECG-1 | A0 High Byte
      TXBuf[4] = 0x00;    //ECG-1 | A0 Low Byte
      TXBuf[5] = 0x02;    //ECG-2 | A1 High Byte
      TXBuf[6] = 0x00;    //ECG-2 | A1 Low Byte
      TXBuf[7] = 0x02;    //PPG   | A2 High Byte
      TXBuf[8] = 0x00;    //PPG   | A2 Low Byte
      TXBuf[9] = 0x02;    //AccX  | I2C High Byte
      TXBuf[10] = 0x00;    //AccX  | I2C Low Byte
      TXBuf[11] = 0x02;   //AccY  | I2C High Byte
      TXBuf[12] = 0x00;   //AccY  | I2C Low Byte
      TXBuf[13] = 0x02;   //AccZ  | I2C High Byte
      TXBuf[14] = 0x00;   //AccZ  | I2C Low Byte
   
      FlexiTimer2::set(4, 1.0/1000, Timer2_Overflow_ISR); //4 units of 1 ms resolution => sampling at FS
      // FlexiTimer2::set(unsigned long units, double resolution, void (*f)())

      FlexiTimer2::start();
      //enables the interrupt.
 
      // Serial Port
      Serial.begin(57600, SERIAL_8N1);       //why this baud rate? too slow vs too many errors

      interrupts();              // Enable all interrupts after initialization has been completed
  }

  void Timer2_Overflow_ISR() {

  // ECG/PPG:
    //Read the ADC channels (ECG-1, ECG-2, PPG)
    for(CurrentCh=0; CurrentCh<3; CurrentCh++) {
      ADC_Value = analogRead(CurrentCh); //first two channels reserved for I2C
      TXBuf[2*CurrentCh + 3] = ((unsigned char)((ADC_Value & 0xFF00) >> 8));// Write High Byte
      TXBuf[2*CurrentCh + 4] = ((unsigned char) (ADC_Value & 0x00FF));	    // Write Low Byte
    }

    // Send Packet
    for(TXIndex=0;TXIndex<15;TXIndex++){
      Serial.write(TXBuf[TXIndex]);
      //delay(100);
    }
    Serial.println("");


    //Serial.println(TXBuf[1], HEX);
    TXBuf[2]++;	                         // Increment the packet counter
    //digitalWrite(13, LOW);

  }

  void loop() {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);                    // starting with register 0x3B (ACCEL_XOUT_H)
    Wire.endTransmission(false);
    Wire.requestFrom(MPU,6,true);        // request 6 (consecutive?) registers
    
    int i = 0;
    while(Wire.available() && i<6) {     // Reads the following 6 registers:
      TXBuf[9+i]=Wire.read();            // 0x3B (ACCEL_XOUT_H), 0x3C (ACCEL_XOUT_L)
      i++;                               // 0x3D (ACCEL_YOUT_H), 0x3E (ACCEL_YOUT_L)
    } 
    //__asm__ __volatile__ ("sleep");
  }

Advertisements

2 thoughts on “pySerial revisited. Some Jason Mraz would be appreciated.

  1. This took way longer than it should have, because I would forget to update all the dependent things in the arduino code – having the wrong packet size for a long time, or mismatch in the baud rates, …
    Even right now, the code attached has a mistake: python’s serial should be configured with no parity.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s