Performing Custom Experiments with PSLab

PSLab has the capability to perform a variety of experiments. The PSLab Android App and the PSLab Desktop App have built-in support for about 70 experiments. The experiments range from variety of trivial ones which are for school level to complicated ones which are meant for college students. However, it is nearly impossible to support a vast variety of experiments that can be performed using simple electronic circuits. So, the blog intends to show how PSLab can be efficiently used for performing experiments which are otherwise not a part of the built-in experiments of PSLab. PSLab might have some limitations on its hardware, however in almost all types of experiments, it proves to be good enough. Identifying the requirements for experiments The user needs to identify the tools which are necessary for analysing the circuit in a given experiment. Oscilloscope would be essential for most experiments. The voltage & current sources might be useful if the circuit requires DC sources and similarly, the waveform generator would be essential if AC sources are needed. If the circuit involves the use and analysis of data of sensor, the sensor analysis tools might prove to be essential. The circuit diagram of any given experiment gives a good idea of the requirements. In case, if the requirements are not satisfied due to the limitations of PSLab, then the user can try out alternate external features. Using the features of PSLab Using the oscilloscope Oscilloscope can be used to visualise the voltage. The PSLab board has 3 channels marked CH1, CH2 and CH3. When connected to any point in the circuit, the voltages are displayed in the oscilloscope with respect to the corresponding channels. The MIC channel can be if the input is taken from a microphone. It is necessary to connect the GND of the channels to the common ground of the circuit otherwise some unnecessary voltage might be added to the channels. Using the voltage/current source The voltage and current sources on board can be used for requirements within the range of +5V. The sources are named PV1, PV2, PV3 and PCS with V1, V2 and V3 standing for voltage sources and CS for current source. Each of the sources have their own dedicated ranges. While using the sources, keep in mind that the power drawn from the PSLab board should be quite less than the power drawn by the board from the USB bus. USB 3.0 - 4.5W roughly USB 2.0 - 2.5W roughly Micro USB (in phones) - 2W roughly PSLab board draws a current of 140 mA when no other components are connected. So, it is advisable to limit the current drawn to less than 200 mA to ensure the safety of the device. It is better to do a rough calculation of the power requirements in mind before utilising the sources otherwise attempting to draw excess power will damage the device. Using the Waveform Generator The waveform generator in PSLab is limited to 5 - 5000 Hz. This range…

Continue ReadingPerforming Custom Experiments with PSLab

SPI Communication in PSLab

PSLab supports communication using the Serial Peripheral Interface (SPI) protocol. The Desktop App as well as the Android App have the framework set-up to use this feature. SPI protocol is mainly used by a few sensors which can be connected to PSLab. For supporting SPI communication, the PSLab Communication library has a dedicated class defined for SPI. A brief overview of how SPI communication works and its advantages & limitations can be found here. The class dedicated for SPI communication with numerous methods defined in them. The methods required for a particular SPI sensor may differ slightly, however, in general most sensors utilise a certain common set of methods. The set of methods that are commonly used are listed below with their functions. In the setParameters method, the SPI parameters like Clock Polarity (CKP/CPOL), Clock Edge (CKE/CPHA), SPI modes (SMP) and other parameters like primary and secondary prescalar which are specific to the device used. Primary Prescaler (0,1,2,3) for 64MHz clock->(64:1,16:1,4:1,1:1) Secondary prescaler (0,1,..7)->(8:1,7:1,..1:1) The values of CKP/CPOL and CKE/CPHA needs to set using the following convention and according to our requirements. At CPOL=0 the base value of the clock is zero, i.e. the idle state is 0 and active state is 1. For CPHA=0, data is captured on the clock's rising edge (low→high transition) and data is changed at the falling edge (high→low transition). For CPHA=1, data is captured on the clock's falling edge (high→low transition) and data is changed at the rising edge (low→high transition). At CPOL=1 the base value of the clock is one (inversion of CPOL=0), i.e. the idle state is 1 and active state is 0. For CPHA=0, data is captured on the clock's falling edge (high→low transition) and data is changed at the rising edge (low→high transition). For CPHA=1, data is captured on the clock's rising edge (low→high transition) and data is changed at the falling edge (high→low transition). public void setParameters(int primaryPreScalar, int secondaryPreScalar, Integer CKE, Integer CKP, Integer SMP) throws IOException { if (CKE != null) this.CKE = CKE; if (CKP != null) this.CKP = CKP; if (SMP != null) this.SMP = SMP; packetHandler.sendByte(commandsProto.SPI_HEADER); packetHandler.sendByte(commandsProto.SET_SPI_PARAMETERS); packetHandler.sendByte(secondaryPreScalar | (primaryPreScalar << 3) | (this.CKE << 5) | (this.CKP << 6) | (this.SMP << 7)); packetHandler.getAcknowledgement(); }   The start method is responsible for sending the instruction to initiate the SPI communication and it takes the channel which will be used for communication as input. public void start(int channel) throws IOException { packetHandler.sendByte(commandsProto.SPI_HEADER); packetHandler.sendByte(commandsProto.START_SPI); packetHandler.sendByte(channel); }   The setCS method is responsible for selecting the slave with which the SPI communication has to be done. This feature of SPI communication is known as Chip Select (CS) or Slave Select (SS). A master can use multiple Chip/Slave Select pins for communication whereas a slave utilises just one pin as SPI is based on single master multiple slaves principle. The capacity of PSLab is limited to two slave devices at a time. public void setCS(String channel, int state) throws IOException { String[] chipSelect = new String[]{"CS1", "CS2"}; channel =…

Continue ReadingSPI Communication in PSLab

I2C Communication in PSLab

PSLab supports communication using the I2C protocol and both the Desktop App and the Android App have the framework set-up to use the I2C protocol. I2C protocol is mainly used by sensors which can be connected to PSLab. For supporting I2C communication, PSLab board has a separate block for I2C communication and has pins named 3.3V, GND, SCL and SDA. A brief overview of how I2C communication works and its advantages & limitations compared to SPI communication can be found here. The PSLab Python and Java communication libraries have a class dedicated for I2C communication with numerous methods defined in them. The methods required for a particular I2C sensor may differ, however, in general most sensors utilise a certain common set of methods. The set of methods that are commonly used are listed below with their functions. For utilising the methods, the I2C bus is first notified using the HEADER byte (it is common to all the methods) and then a byte to uniquely determine the method in use. The send method is used to send the data over the I2C bus. First the I2C bus is initialised and set to the correct slave address using I2C.start(address) followed by this method. The method takes the data to be sent as the argument. def send(self, data): try: self.H.__sendByte__(CP.I2C_HEADER) self.H.__sendByte__(CP.I2C_SEND) self.H.__sendByte__(data) # data byte return self.H.__get_ack__() >> 4 except Exception as ex: self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)   The read method reads a fixed number of bytes from the I2C slave. One can also use I2C.simpleRead(address,  numbytes) instead to read from the I2C slave. This method takes the length of the data to be read as argument.  It fetches length-1 bytes with acknowledge bits for each. def read(self, length): data = [] try: for a in range(length - 1): self.H.__sendByte__(CP.I2C_HEADER) self.H.__sendByte__(CP.I2C_READ_MORE) data.append(self.H.__getByte__()) self.H.__get_ack__() self.H.__sendByte__(CP.I2C_HEADER) self.H.__sendByte__(CP.I2C_READ_END) data.append(self.H.__getByte__()) self.H.__get_ack__() except Exception as ex: self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name) return data   The readBulk method reads the data from the I2C slave. This takes the I2C slave device address, the address of the device from which the data is to be read and the length of the data to be read as argument and the returns the bytes read in the form of a list. def readBulk(self, device_address, register_address, bytes_to_read): try: self.H.__sendByte__(CP.I2C_HEADER) self.H.__sendByte__(CP.I2C_READ_BULK) self.H.__sendByte__(device_address) self.H.__sendByte__(register_address) self.H.__sendByte__(bytes_to_read) data = self.H.fd.read(bytes_to_read) self.H.__get_ack__() try: return [ord(a) for a in data] except: print('Transaction failed') return False except Exception as ex: self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)   The writeBulk method writes the data to the I2C slave. It takes address of the particular I2C slave for which the data is to be written and the data to be written as arguments. def writeBulk(self, device_address, bytestream): try: self.H.__sendByte__(CP.I2C_HEADER) self.H.__sendByte__(CP.I2C_WRITE_BULK) self.H.__sendByte__(device_address) self.H.__sendByte__(len(bytestream)) for a in bytestream: self.H.__sendByte__(a) self.H.__get_ack__() except Exception as ex: self.raiseException(ex, "Communication Error , Function : " + inspect.currentframe().f_code.co_name)   The scan method scans the I2C port for connected devices which utilise I2C as a communication mode. It takes…

Continue ReadingI2C Communication in PSLab

The Pocket Science Lab: Who Needs it, and Why

Science and technology share a symbiotic relationship. The degree of success of experimentation is largely dependent on the accuracy and flexibility of instrumentation tools at the disposal of the scientist, and the subsequent findings in fundamental sciences drive innovation in technology itself. In addition to this, knowledge must be free as in freedom. That is, all information towards constructing such tools and using them must be freely accessible for the next generation of citizen scientists. A common platform towards sharing results can also be considered in the path to building a better open knowledge network. But before we get to scientists, we need to consider the talent pool in the student community that gave rise to successful scientists, and the potential talent pool that lost out on the opportunity to better contribute to society because of an inadequate support system. And this brings us to the Pocket Science Lab How can PSLab help electronics engineers & students? This device packs a variety of fundamental instruments into one handy package, with a Bill-of-materials that’s several orders of magnitude less than a distributed set of traditional instruments. It does not claim to be as good as a Giga Samples Per second oscilloscope, or a 22-bit multimeter, but has the potential to offer a greater learning experience. Here’s how: A fresh perspective to characterize the real world. The visualization tools that can be coded on an Android device/Desktop (3D surface plots, waterfall charts, thermal distributions etc ), are far more advanced than what one can expect from a reasonably priced oscilloscope. If the same needs to be achieved with an ordinary scope, a certain level of technical expertise is expected from the user who must interface the oscilloscope with a computer, and write their own acquisition & visualization app. Reduce the entry barrier for advanced experiments.: All the tools are tightly integrated in a cost-effective package, and even the average undergrad student that has been instructed to walk on eggshells around a conventional scope, can now perform elaborate data acquisition tasks such as plotting the resonant frequency of a tuning fork as a function of the relative humidity/temperature. The companion app is being designed to offer varying levels of flexibility as demanded by the target audience. Is there a doctor in the house? With the feature set available in the PSlab , most common electronic components can be easily studied , and will save hours while prototyping new designs.  Components such as resistors, capacitors, diodes, transistors, Op-amps, LEDs, buffers etc can be tested. How can PSLab help science enthusiasts ? Physicists, Chemists and biologists in the applied fields are mostly dependent on instrument vendors for their measurement gear. Lack of an electronic/technical background hinders their ability to improve the gear at their disposal, and this is why a gauss meter which is basically a magnetometer coupled with a crude display in an oversized box with an unnecessarily huge transformer can easily cost upwards of $150 . The PSLab does not ask the user…

Continue ReadingThe Pocket Science Lab: Who Needs it, and Why

Real time Sensor Data Analysis on PSLab Android

PSLab device has the capacity to connect plug and play sensors through the I2C bus. The sensors are capable of providing data in real time. So, the PSLab Android App and the Desktop app need to have the feature to fetch real time sensor values and display the same in the user interface along with plotting the values on a simple graph. The UI was made following the guidelines of Google’s Material Design and incorporating some ideas from the Science Journal app. Cards are used for making each section of the UI. There are segregated sections for real time updates and plotting where the real time data can be visualised. A methods for fetching the data are run continuously in the background which receive the data from the sensor and then update the screen. The following section denotes a small portion of the UI responsible for displaying the data on the screen continuously and are quite simple enough. There are a number of TextViews which are being constantly updated on the screen. Their number depends on the type and volume of data sent by the sensor. <TextView android:layout_width="wrap_content" android:layout_height="30dp" android:layout_gravity="start" android:text="@string/ax" android:textAlignment="textStart" android:textColor="@color/black" android:textSize="@dimen/textsize_edittext" android:textStyle="bold" /> <TextView android:id="@+id/tv_sensor_mpu6050_ax" android:layout_width="wrap_content" android:layout_height="30dp" android:layout_gravity="start" android:textAlignment="textStart" android:textColor="@color/black" android:textSize="@dimen/textsize_edittext" android:textStyle="bold" />   The section here represents the portion of the UI responsible for displaying the graph. Like all other parts of the UI of PSLab Android, MPAndroidChart is being used here for plotting the graph. <LinearLayout android:layout_width="match_parent" android:layout_height="160dp" android:layout_marginTop="40dp"> <com.github.mikephil.charting.charts.LineChart android:id="@+id/chart_sensor_mpu6050" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000" /> </LinearLayout>   Since the updates needs to continuous, a process should be continuously run for updating the display of the data and the graph. There are a variety of options available in Android in this regard like using a Timer on the UI thread and keep updating the data continuously, using ASyncTask to run a process in the background etc. The issue with the former is that since all the processes i.e. fetching the data and updating the textviews & graph will run on the UI thread, the UI will become laggy. So, the developer team chose to use ASyncTask and make all the processes run in the background so that the UI thread functions smoothly. A new class SensorDataFetch which extends AsyncTask is defined and its object is created in a runnable and the use of runnable ensures that the thread is run continuously till the time the fragment is used by the user. scienceLab = ScienceLabCommon.scienceLab; i2c = scienceLab.i2c; try { MPU6050 = new MPU6050(i2c); } catch (IOException e) { e.printStackTrace(); } Runnable runnable = new Runnable() { @Override public void run() { while (true) { if (scienceLab.isConnected()) { try { sensorDataFetch = new SensorDataFetch(); } catch (IOException e) { e.printStackTrace(); } sensorDataFetch.execute(); } } } }; new Thread(runnable).start();   The following is the code for the ASyncTask created. There are two methods defined here doInBackground and onPostExecute which are responsible for fetching the data and updating the display respectively. The raw data is fetched using the getRaw…

Continue ReadingReal time Sensor Data Analysis on PSLab Android

Packing and Unpacking Data in PSLab Android App

In PSLab we communicate with PSLab Hardware device, to exchange data, i.e we give a command or instruction and it responses accordingly. So this giving and receiving is in terms of packed byte string. Thus, we need some solid knowledge to pack and unpack data. In python communication library, there is struct module available. In JAVA we can use NIO’s ByteBuffer or implement our own functions. In this blog post I discuss both methods.   In Python we have struct module for packing data in byte strings. As different languages interpret data types differently like Java takes 4 bytes for int and C++ takes 2 bytes for int. To send and receive data properly, we pack data in a byte string and unpack on other side with it's data type properties. In PSLab, we have to communicate with device for various applications like getting calibration data during power up time as raw data doesn’t make much sense until calibration is applied on it. You also need to take care of order of sequence of bytes like there are generally two types of order in which a sequence of bytes are stored in memory location: Big - Endian: In which MSB is stored first. Little - Endian: In which LSB is stored first. In Python The standard sizes and format characters of particular data type can be seen in the image below. Format C Type Python Type Standard x Pad byte No value c char string of length 1 1 b signed char integer 1 B unsigned char integer 1 ? _Bool bool 1 h short integer 2 H unsigned short integer 2 i int integer 4 I unsigned int integer 4 l long integer 4 L unsigned long integer 4 q long long integer 8 Q unsigned long long integer 8 f float float 4 d double float 8 s char[] string p char[] string P void* integer Source: Python Docs For Packing data import struct struct.Struct("B").pack(254)   # Output ->  b'\xfe' a = struct.Struct("I").pack(2544)   # Output -> b'\xf0\t\x00\x00' Now a is the byte string that has packed value as 2544, this can be send to some device byte by byte and reconstructed on receiving side by knowing how many bytes does the data type received contains. For Unpacking data import struct struct.unpack("I",a)  # Output -> (2544,) In JAVA For Packing data Suppose you have to pack an integer, in java int takes 32 bits (4 bytes) Using JAVA’s NIO’s ByteBuffer byte[] bytes = ByteBuffer.allocate(4).putInt(2544).array(); If you want hardcore method to see what exactly is happening, use byte[] intToByteArray(int value){  return new byte[]{     (byte)value >>> 24,     (byte)value >>> 16,     (byte)value >>> 8,     (byte)value  }; } ">>>" is used for unsigned shifting, you can use according to your requirements. After you have your byte array, you can easily create a string out of it and transmit. For Unpacking data Using JAVA’s NIO’s ByteBuffer int fromByteArray(byte[] bytes){ int a = ByteBuffer.wrap(bytes).getInt(); return a; } It assumes that byte array is stored as…

Continue ReadingPacking and Unpacking Data in PSLab Android App

Communication by pySerial python module in PSLab

In the PSLab Desktop App we use Python for communication between the PC and PSLab device. The PSLab device is connected to PC via USB cable. The power for the hardware device is provided by the host through USB which in this case is a PC. We need well structured methods to establish communication between PC and PSLab device and this is where pySerial module comes in. We will discuss how to communicate efficiently from PC to a device like PSLab itself using pySerial module. How to read and write data back to PSLab device? pySerial is a python module which is used to communicate serially with microcontroller devices like Arduino, RaspBerry Pi, PSLab (Pocket Science Lab), etc. Serial data transfer is easier using this module, you just need to open a port and obtain serial object, which provides useful and powerful functionality. Users can send string (which is an array of bytes) or any other data type all data types can be expressed as byte string using struct module in python, read a specific number of bytes or read till some specific character like ‘\n’ is encountered. We are using this module to create custom read and write functions. How to Install pySerial and obtain serial object for communication? You can install pySerial using pip by following command pip install pyserial Once it's installed we can now import it in our python script for use. Obtain Serial Object In Linux >>> import serial >>> ser = serial.Serial('/dev/ttyUSB0') In Windows >>> ser = serial.Serial() >>> ser.baudrate = 19200 >>> ser.port = 'COM1' Or >>> ser = serial.Serial('COM1', 19200) You can specify other properties like timeout, stopbits, etc to Serial constructor. Complete list of parameters is available here. Now this “ser” is an object of Serial class that provides all the functionalities through its interface. In PSLab we obtain a serial object and implement custom methods to handle communication which isn’t directly provided by pySerial, for example if we need to implement a function to get the version of the PSLab device connected. Inside the version read function we need to send some bytes to the device in order to obtain the version string from device as a byte response. What goes under the hood? We send some sequence of bytes to PSLab device, every sequence of bytes corresponds to a unique function which is already written in device’s firmware. Device recognises the function and responses accordingly. Let's look at code to understand it better. ser.write(struct.Struct('B').pack(11))  #  Sends 11 as byte string ser.write(struct.Struct('B').pack(5))   #  Sends 5 as bytes string x = ser.readline()                      #  Reads bytes until ‘\n’ is encountered    To understand packing and unpacking using struct module, you can have a read at my other blog post Packing And Unpacking Data in JAVA in which I discussed packing and unpacking of data as byte strings and touched a bit on How it's done in Python.   You can specify how many bytes you want to read like shown in code…

Continue ReadingCommunication by pySerial python module in PSLab

Analyzing Sensor Data on PSLab

PSLab Android App and Desktop app have the functionality of reading data from the sensors. The raw sensor data received is in the form of a long string and needs to parsed to understand what the data actually conveys. The sensor data is unique in terms of volume of data sent, the units of measurement of the data etc., however none of this is reflected in the raw data. The blog describes how the sensor data received by the Android/Desktop app is parsed, interpreted and finally presented to the user for viewing. The image below displays the raw data sent by the sensors Fig: Raw Sensor data displayed below the Get Raw button In order to understand the data sent from the sensor, we need to understand what the sensor does. For example, HMC5883L is a 3-axis magnetometer and it returns the value of the magnetic field in the x, y & z axes in the order of nanoTeslas. Similarly, the DAC of PSLab - MCP4728 can also be used like other sensors, it returns the values of channels in millivolts. The sensor MPU6050 being 3-axes accelerometer & gyroscope which returns the values of acceleration & angular momentum of the x, y & z axes in their SI units respectively. Each sensor has a sensitivity value. The sensitivity of the sensor can be modified to adjust the accuracy of the data received. For PSLab, the data returned is a float number with each data point having 4 bytes of memory with the highest sensitivity. Although sensitivity is not a reliable indicator of the accuracy of the data. Each value received has a lot of trailing values after the decimal and it is evident that no sensor can possibly achieve accuracy that high, so the data after 2-3 decimal places is garbage and not taken into consideration. Some sensors are configurable up to a great extent like MPU6050 where limits can also be set on the range of data, volume of data sent etc. whereas some are not configurable and are just meant for sending the data at regular intervals. In order to parse the above data, if the sensor returns a single value, then the data is ready to be used. However, in most cases like above where the sensors return multiple values, the data stream can be divided into equal parts since each value occupies equal space and each value can be stored in different variables. The stored data has to be presented to the user in a better understandable format where it is clear that what each value represents. For example, in case of the 3 axes sensors, the data of each axis must be distinctly represented to the user. Shown below are the mock-ups of the sensor UIs in which each value has been distinctly represented.           Fig: Mock-ups for the sensor UIs (a) - HMC5883L (b) - MPU6050 Each UI has a card to display those values. These values are updated in…

Continue ReadingAnalyzing Sensor Data on PSLab