Friday, 15 June 2018

Detecting and tracking QR codes in Python

QR or Quick Response codes have become ubiquitous. I figured that some of might be looking to use them in your applications so I decided to write this tutorial which will cover QR code detection, some plotting and tracking and a neat way to build a GUI using Tkinter.

What you will need for this tutorial (I am assuming that you are on a Linux based installation) :

1. Python installation : Python 2.7.x onwards.
 
    sudo apt-get install python

2. Open_CV , pyzbar , Tkinter:
 

     sudo apt-get install libzbar0
     sudo pip install opencv-python
     sudo pip install pyzbar
     sudo apt-get install python-tkinter


Now you are all set to write some code on python which will detect QR codes and Display their values and draw their paths on screen.


I will explain it section wise below :

# First importing the packages in your python Code.

import pyzbar.pyzbar as pyzbar
import numpy as np
import cv2
import Tkinter as tk
import math


#Global Variables
 track_points=[ ]      #All stored points of positions of QR_Codes.

#Creating a Quit Button Using Tkinter
   root=tk.Tk()
frame=tk.Frame(root)
frame.pack()
button=tk.Button(frame,text="Destroy",command=destroy)
button.pack(side=tk.LEFT)
 

#Initializing Your WebCam for video Capture Using OpenCv


cap = cv2.VideoCapture('0')
 

 #A loop that will keep running and processing each frame captured
while(True):
    #Updates the Tkinter GUI
    root.update()


    ret, frame = cap.read()

    # Our operations on the frame come here    

    im = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    #All Detected QR_codes are stored as decoded Objects   

    decodedObjects= decode(im)
    

     
    #If there are Detected Codes, Computations are performed
    if (len(decodedObjects)>0):           
        compute(im,decodedObjects)
        
    

    cv2.imshow("Results", im)   
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
button.destroy()
cap.release()
cv2.destroyAllWindows()




I will Now describe the compute and track_object user Functions used Above. Keep in mind that the Decoded Objects has two attributes of use :

1. .polygon : All corner point of the detected QR_code
2. .data :       Data encoded by the QR_Code

def decode(im) :
  # Find barcodes and QR codes
  decodedObjects = pyzbar.decode(im)

  # Print results
  #for obj in decodedObjects:
    #print('Type : ', obj.type)
    #print('Data : ', obj.data,'\n')
    
  return decodedObjects


This Function will compute the centre of each QR Code, using mean of points in the polygon attribute. It will then put the data of the QR code at its centre
 
def compute(im, decodedObjects):
  # Loop over all decoded objects
  for decodedObject in decodedObjects:
        points = decodedObject.polygon
         

         centre=find_centre(points)   
        #print ("Object:", points,'\n')       
        #print ("Centre:", centre, '\n')
    cv2.circle(im,centre,10,(0,0,255),-1)
    cv2.putText(im,decodedObject.data,centre,cv2.FONT_HERSHEY_SIMPLEX, 1, 255)

        if centre in track_points:
                    #Do Something
        else:
             track_points.append(centre)

    for point in track_points:
            cv2.circle(im,point,3,(0,0,255),-1)


This Function Computes the centre of the QR_Code and returns it
 
def find_centre(points):
     x_mean=0
     y_mean=0       
     for point in points:
            x,y=point
            x_mean+=x
            y_mean+=y
     #calculate mean of points
     return (x_mean/len(points) , y_mean/len(points))





Finally the destroy function, which will close all windows and release the camera


def destroy():
        button.destroy()
        cap.release()
        cv2.destroyAllWindows()   
    button1.destroy()









Hope You have Fun Extending this code and build exciting things with it.

       

Friday, 24 November 2017

Triboelectricity And Nano-generators

We all have experienced some consequence of the Tribo-electric effect. It is the same phenomenon that is responsible for electric shocks when you sometimes touch a piece of metal or when you take off your wool sweater in winter. We studied the famous experiment of rubbing the a comb against your hair and see it attract pieces of paper. Tribo-electric effect is the phenomenon of contact electrification between two surfaces of different electron affinities.

This effect has been known since time immemorial , but was mostly associated as a hazard that would destroy electronic parts and hamper industrial processes. However , of late this process is being studied in the light of harvesting this energy to power Internet of Things device , sensors and wearable tech that would need no batteries.  It is an exciting exploration being pioneered by Prof. Zhong Lin Wang and his group at the Georgia Institute of Technology , U.S.A. The research aims not only to harness the milli joules of wasted energy of human actions but also explore Triboelectric effect as a alternative source of energy to power the ever rising energy needs of the world. His publications talk about harvesting the energy from waves in the ocean using this effect. The research group at Georgia Tech has tried grating materials to achieve a high output power and efficiency.

Even without such expensive nano fabrication , one can use household materials to witness the potential and magic of this effect. All you need is two materials with different electron affinities to rub together and then harness this energy to put to some use. The triboelectric series is an arrangement of material ranked according to their electron affinities. Ideally you would like to choose substances as far apart in this series. A good combination is PTFE( Teflon paper )  and paper ( newspaper , office grade paper ). These when rubbed together will produce AC output. For any DC applications you would need a rectifier circuit to convert AC to DC. Since the current output is in micro amperes, you would also need a charge storing mechanism in the form of a capacitor.

Below are some publications by Prof. Zhong Lin Wang and folks at Disney Research who have put this concept to interesting uses.

Disney Research : Paper Generators
Publication by Prof. Zhong Lin Wang
  

Thursday, 17 August 2017

CAPACITIVE SENSING

Capacitive sensing is an amazing technology that finds application in a variety of sensing applications. The most familiar example is the capacitive touch screen on your phone or the touch buttons on your micro-wave. At the heart of all these applications is a capacitance to digital converter that enables the device to track the changes that your finger makes by acting as the ground plate of the capacitor. I had my own adventures with this technology while designing a high resolution level sensing device.

I used FDC1004 (capacitance to digital converter) manufactured by Texas instruments. It has four channels and is resistant to EMI.  Texas instruments also provides a nice Evaluation module with GUI support for quick prototyping. Depending on your application , you can choose from other devices with different capacitance sensing ranges. The sensing range for FDC1004 is -15pF to +15pF. The Chip uses I2C communication for data exchange and configuration with a master Micro-controller. The micro-controller that I used was Atmega1248P.

Here is a link to the datasheet of FDC2214 :Datasheet

Based on the application notes provided by Texas Instruments , I was able to use the FDC2214 to design a sensor for liquid level sensing. For anyone else in the game looking to use this technology, this link can help you to get started with your own firmware for this device.

Basics of Capacitive sensing : Click Here

GitHUB : https://github.com/suveergarg/FDC_1004-capacitive-water-level-sensing

Please Feel free to post any questions regarding my code if you feel it is unclear. I have chosen to have only file and not tried to separate the TWI library. All functions of the TWI library are defined in the main.c file itself.


Capacitive sensing based liquid level sensor : Here is how my sensor looked. It has three capacitors. The top pair are for environment sensing. The middle is the main level sensor while the bottom pair acts as reference sensor and always remains dipped in a typical application.The surrounding layer acts as a shield against EMI interference. The pins outs are connected to the respective pins on the FDC2214 chip.

I was able to get a fairly linear graph for all my tests and the sensor was able to distinguish changes < 1mm in the height of the liquid.

                                                                   




                                                                       
                                                                   
 

Friday, 13 January 2017

I2C Communication Protocol

I2C stands for Inter-Integrated Circuit. It is a serial communication protocol which allows for multiple masters and multiple slaves. It was invented by NXP Semiconductors.

I2C uses two bi-directional open drain lines ,SDA (Serial Data Line) and SCL(Serial Clock Line), pulled up with resistors.

The maximum number of nodes is limited by the address space and also by the total bus capacitance, which restricts communication distances to a few metres.

Master Node  generates the clock and initiates communication with slaves.
Slave Node receives the clock and responds when addressed by master.

Multi-Master , Multi-slave bus means that any number of master and slave nodes can be present. Master and slave nodes may interchange roles between messages.

There may be four potential modes of operation for a given bus device, although most devices only use a single role and its two modes:
  • master transmit — master node is sending data to a slave
  • master receive — master node is receiving data from a slave
  • slave transmit — slave node is sending data to the master
  • slave receive — slave node is receiving data from the master
The master is initially in master transmit mode by sending a start bit followed by the 7-bit address of the slave it wishes to communicate with, which is finally followed by a single bit representing whether it wishes to write(0) to or read(1) from the slave.
If the slave exists on the bus then it will respond with an ACK bit (active low for acknowledged) for that address. The master then continues in either transmit or receive mode (according to the read/write bit it sent), and the slave continues in its complementary mode (receive or transmit, respectively).

APPLICATIONS :
 I2C is used in embedded systems application where simplicity and manufacturing costs outweigh the need of high speed.
1. Reading configuration data from SPD EEPROMs, SDRAM , DDR SDRAM
2. Accessing Low speed ADCs and DACs
3.Controlling OLED/LCD displays, like in a cellphone.
4.Reading Real Time Clocks.
5.Turning on and turning off the power supply of system components.

A particular strength of I2C is the capability of the micro controller to control a host of devices woth just two general purpose I/O pins and software. Many other bus technologies such as SPI, require more pins and signals to connect devices.

CODE

#define F_CPU 16000000UL                                    // Clock speed

#include <avr/io.h>
#include <util/delay.h>
#include <util/twi.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX_TRIES 50
#define BAUD 9600                                           //Baud Rate:9600
#define BAUD_PRESCALE (((F_CPU / (BAUD * 16UL))) - 1)

void TWI_start(void);
void TWI_repeated_start(void);
void TWI_init_master(void);
void TWI_write_address(unsigned char);
void TWI_read_address(unsigned char);
void TWI_write_data(unsigned char);
void TWI_read_data(void);
void TWI_stop(void);
void USART_send( unsigned char );
void USART_init(void);

int main(void)
{
    USART_init();
   
    TWI_init_master();
   
     while(1)
     {
     
      // Your Application code
      // Using the functions below, you can make your own read and write frames to suit different     
         devices
      }
}

void USART_init(void)
{
   
    UCSR0B |= (1<<RXEN0)  | (1<<TXEN0);
    UCSR0C |= (1<<UCSZ00) | (1<<UCSZ01);
    UBRR0H  = (BAUD_PRESCALE >> 8);
    UBRR0L  = BAUD_PRESCALE;
}
void USART_send(unsigned char data)
{
    while(!(UCSR0A & (1<<UDRE0)));
    UDR0 = data;
}
void TWI_init_master(void) // Function to initialize master
{
    TWBR=0x48;  // Bit rate
    TWSR=(0<<TWPS1)|(0<<TWPS0); // Setting prescalar bits
    // SCL freq= F_CPU/(16+2(TWBR).4^TWPS)
}
void TWI_start(void)
{
    // Clear TWI interrupt flag, Put start condition on SDA, Enable
       TWI
    TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while(!(TWCR & (1<<TWINT))); 
    // Wait till start condition is transmitted
    while((TWSR & 0xF8)!= TW_START)USART_send('e'); 
    // Check for the acknowledgement
}
void TWI_repeated_start(void)
{
    
    // Clear TWI interrupt flag, Put start condition on SDA, Enable
       TWI
    TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while(!(TWCR & (1<<TWINT))); 
    // Wait till start condition is transmitted
    while((TWSR & 0xF8)!= TW_REP_START); 
    // Check for the acknowledgement
}
void TWI_write_address(unsigned char data)
{
    TWDR=data;// Address and write instruction
   
    TWCR=(1<<TWINT)|(1<<TWEN);   
    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT)));
    // Wait till complete TWDR byte transmitted
  
    while((TWSR & 0xF8)!= TW_MT_SLA_ACK)USART_send('e'); 
    // Check for the acknowledgement
    //USART is used for debugging
}
void TWI_read_address(unsigned char data)
{
    TWDR=data;  // Address and read instruction
    TWCR=(1<<TWINT)|(1<<TWEN);    
    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT)));
    // Wait till complete TWDR byte received
    while((TWSR & 0xF8)!= 0x40);  
    // Check for the acknowledgement
}
void TWI_write_data(unsigned char data)
{
    TWDR=data;  // put data in TWDR
    TWCR=(1<<TWINT)|(1<<TWEN);   
    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT)));
    // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != TW_MT_DATA_ACK); 
    // Check for the acknowledgement
}
void TWI_read_data(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);  
    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT))); 
    // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != TW_MR_DATA_ACK); 
    // Check for the acknowledgement
}
void TWI_read_dataN(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN);    
    // Clear TWI interrupt flag,Enable TWI
    while (!(TWCR & (1<<TWINT)));
    // Wait till complete TWDR byte transmitted
    while((TWSR & 0xF8) != TW_MR_DATA_NACK);
    // Check for the acknowledgement
}
void TWI_stop(void)
{
    // Clear TWI interrupt flag, Put stop condition on SDA, Enable
       TWI
    TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
    while(!(TWCR & (1<<TWSTO))); 
    // Wait till stop condition is transmitted
}




Sunday, 28 August 2016

Serial Communication

I have been experimenting with serial communication for a while now, trying to figure out how I build an application of my own that is capable of using the serial port for communication.

Following is an instruction to help you employ it in your own applications :

Download the serial library (libserial) from the link below :

https://github.com/crayzeewulf/libserial

 Unpack and navigate to the directory using the command terminal :

cd  <directory of the unpacked libserial folder>

 

Generate configure file : make -f Makefile.dist
Configure :                     ./configure
Make and install :             make & make install


The libraries will have now installed to /usr/local/lib and include files in /usr/local/include. You can navigate to these folders and check.


I work in a Workspace directory. Navigate to the directory where you store your programs and run :

gedit Serial_Monitor.cpp

I used the following code for my application , borrowing from the libserial examples :

#include <SerialStream.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <fstream>

using namespace LibSerial;
   
int main(int argc, char** argv)
{
    // Instantiate the SerialStream object then open the serial port.
    SerialStream serial_stream;
    serial_stream.Open("/dev/ttyACM0");
   
    if(argc<2)
    {
      std::cerr<< "Usage: " << argv[0] << " <filename>" << std::endl ;
        return 1 ;
    }


    if ( !serial_stream.good() )
    {
        std::cerr << "[" << __FILE__ << ":" << __LINE__ << "] "
                  << "Error: Could not open serial port."
                  << std::endl ;
        exit(1) ;
    }

    // Set the baud rate of the serial port.
    serial_stream.SetBaudRate(SerialStreamBuf::BAUD_9600);
   
    if ( !serial_stream.good() )
    {
        std::cerr << "Error: Could not set the baud rate." << std::endl ;
        exit(1) ;
    }

    // Set the number of data bits.
    serial_stream.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
   
    if ( !serial_stream.good() )
    {
        std::cerr << "Error: Could not set the character size." << std::endl ;
        exit(1) ;
    }

    // Disable parity.
    serial_stream.SetParity( SerialStreamBuf::PARITY_NONE ) ;
   
    if ( !serial_stream.good() )
    {
        std::cerr << "Error: Could not disable the parity." << std::endl ;
        exit(1) ;
    }

    // Set the number of data bits.
    serial_stream.SetCharSize( SerialStreamBuf::CHAR_SIZE_8 ) ;
   
    if ( !serial_stream.good() )
    {
        std::cerr << "Error: Could not set the character size." << std::endl ;
        exit(1) ;
    }


    // Set the number of stop bits.
    serial_stream.SetNumOfStopBits(1);
   
    if (!serial_stream.good())
    {
        std::cerr << "Error: Could not set the number of stop bits."
                  << std::endl ;
        exit(1) ;
    }

    // Turn off hardware flow control.
    serial_stream.SetFlowControl(SerialStreamBuf::FLOW_CONTROL_NONE);
    if ( !serial_stream.good() )
    {
        std::cerr << "Error: Could not use hardware flow control."
                  << std::endl ;
        exit(1) ;
    }


    // Open the input file for reading.
    std::ifstream input_file( argv[1] );
   
    if ( !input_file.good() )
    {
        std::cerr << "Error: Could not open file "
                  << argv[1] << " for reading." << std::endl ;
        return 1 ;
    }

    // Read characters from the input file and dump them to the serial port.
    std::cerr << "Dumping file to serial port." << std::endl ;
   
    while( input_file )
    {
        char nextByte;
        input_file.read( &nextByte, 1 ) ;
        serial_stream.write( &nextByte, 1 ) ;
        while( serial_stream.rdbuf()->in_avail() == 0 )
        {
          usleep(100) ;
        }

        if(serial_stream.rdbuf()->in_avail() > 0)
          {
             char nextByte;
             serial_stream.get(nextByte);
             std::cerr << ( nextByte ) << " " ;
             usleep(100) ;
          }

    }
    std::cerr << std::endl ;
    std::cerr << "Done." << std::endl ;   
    return EXIT_SUCCESS ;
}
 
Save. Compile and link with :

  g++ -o serial_monitor Serial_Monitor.cpp -lserial -lpthread
 

In your working directory , create a file called input and put random characters in it.

You can now run your program :

./serial_monitor input

// it will take characters from the input file and write it to the serial port.

 Upload the following sketch to your Arduino


 void setup()
{
  Serial.begin(9600);
}

void loop()
{
 
 char input =Serial.read();
 Serial.print(input);
 delay(100);
}

 

At a Baud rate of 9600 this program will echo the values it receives on the serial port.


Run your program :

If you face errors, try the following:

 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
// To add Library Path to shell

sudo chmod a+rw /dev/ttyACM0
// to Change permission to access port



./serial_monitor input


(My input file had : a b  c d) The arduino echoes these values , which your program reads and displays on the terminal.

If you are having trouble following the tutorial above , feel free to discuss it in the comments.