User Tools

Site Tools


lego_nxt_optical_sensor

This is an old revision of the document!


Get data from Optical Sensor SPCP168A and display in LEGO NXT

1, Optical Sensor Mouse SPCP168A

Description

The SPCP168A sensor SoC is a low-cost single-chip optical mouse. The general solution used to implement a non-mechanical tracking engine for computer mice. It is based on SPCP138A optical navigation technology which measures changes in position by optically acquiring sequential surface images and mathematically determining the direction and magnitude of movement. The General optical mouse SoC provides a complete and compact mouse solution. There are no moving parts, and precision optical alignment is not required, few outside components use and facilitate high volume assembly.

Structure of optical mouse sensor.

The SPCP168A is in an SFF (Small form factor) symmetrical PDIP14-pin optical package and comes with multiple CPI(counts per inch) resolution by CPI button switching and the speed of motion up to 25 inches per second. It includes 3 generally buttons (R、M、L); X-Y motion and a mechanical wheel encoding (1:2)for vertical scrolling and 2 extra 4th / 5th buttons optional.

USB MCU inside so that it’s no more mouse controller is needed to interface through USB. The SPCP168A can receive USB command and echo status or data format, both complete USB spec V2.0 and USB HID spec V1.1 compatibility. It is also a cost-effective solution to support USB Optical Mouse.

Application Circuit

2, PS/2 protocal

PS/2 connection

The PS/2 connection is the IBM standard protocol to communicate keyboard, PC mouse with your computer. This protocol has the responsibility to send the key scan codes that you press to the pc and get some response commands from it. This means that we are dealing with a bi-directional type of protocol as each device (pc/keyboard) sends and receives commands.

The PS/2 controller interface consists of the PS/2 clock and the PS/2 data inputs, and two 8-bit data ports. One of the 8-bit data ports is used for sending commands to the PS/2 device (mouse or keyboard), the other is for receiving data from the PS/2 device. There are also control signals provided to indicate the arrival of a new command from the PS/2 device and the status of the command transmission to the PS/2 device. The timing control necessary for the PS/2 communication is handled by the controller.

PS/2 mouse data packets

All data is transmitted one byte at a time and each byte is sent in a frame consisting of 11 bits. These bits are:

  • 1 start bit
  • 8 data bits
  • 1 parity bit
  • 1 stop bit

The mouse keeps track of movement around the X-Y space and the state of its buttons by use of counters. The content of these counters is periodically sent to the host in the form a 4-byte movement data packet. The movement counters represent the mouse's offset relative to its position when the previous movement data packet was issued.

data
------------------------
    D7 D6 D5 D4 D3 D2 D1 D0  (The D0 bit (LSB) is sent first)
------------------------
(1) YV XV YS XS  1  M  R  L  (overflow, sign, buttons)
(2) X7 X6 X5 X4 X3 X2 X1 X0  (X movement; -128 to +127)
(3) Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0  (Y movement; -128 to +127)
(4) Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0  (Z movement; -128 to +127)
 
M  = Middle Button State (1 = pressed down)
L  = Left  Button State (1 = pressed down)
R  = Right Button State (1 = pressed down)
XS = Direction of X movement (1 = LEFT)
YS = Direction of Y movement (1 = UP)
XV = Overflow of X movement value (1 = X overflow occured)
YV = Overflow of Y movement value (1 = Y overflow occured)
X7,...,X0 : X movement; 8-bit 2's-complement signed byte (-128 to +127)
Y7,...,Y0 : Y movement; 8-bit 2's-complement signed byte (-128 to +127)
Z7,...,Z0 : Mouse wheel movement; 8-bit 2's-complement signed byte
    (The Z value is forced to a range of -8 to +7)

3, Materials and Software

Materials and Sources

This tutorial using Arduino UNO to reading the data from optical mouse using SPCP168A chip, then send data to LEGO NXT via I2C protocol.

Software and Sources

  • Arduino ide
  • ROBOTC for LEGO Mindstorms

4, Interface A Sensor Mouse with Arduino via PS/2 protocol

Connection

Code

PS/2 Write

Write byte
void writeByte(char data) {
    int parityBit = 1;
    high(_dataPin);//set pin high
    high(_clockPin);//set pin high
    delayMicroseconds(300);
    low(_clockPin);//set pin low
    delayMicroseconds(300);
    low(_dataPin);//set pin low
    delayMicroseconds(10);
 
    // start bit
    high(_clockPin);
    waitForClockState(LOW);
    // data
    for (int i = 0; i < 8; i++) {
        int dataBit = bitRead(data, i);
        writeBit(dataBit);
        parityBit = parityBit ^ dataBit;
    }
 
    // parity bit
    writeBit(parityBit);
 
    // stop bit
    high(_dataPin);
    delayMicroseconds(50);
    waitForClockState(LOW);
 
    // wait for mouse to switch modes
    while ((digitalRead(_clockPin) == LOW) || (digitalRead(_dataPin) == LOW))
        ;
    // put a hold on the incoming data
    low(_clockPin);
}

PS/2 Reading

Readbyte
void writeByte(char data) {
    int parityBit = 1;
    high(_dataPin);//set pin high
    high(_clockPin);//set pin high
    delayMicroseconds(300);
    low(_clockPin);//set pin low
    delayMicroseconds(300);
    low(_dataPin);//set pin low
    delayMicroseconds(10);
 
    // start bit
    high(_clockPin);
    waitForClockState(LOW);
    // data
    for (int i = 0; i < 8; i++) {
        int dataBit = bitRead(data, i);
        writeBit(dataBit);
        parityBit = parityBit ^ dataBit;
    }
 
    // parity bit
    writeBit(parityBit);
 
    // stop bit
    high(_dataPin);
    delayMicroseconds(50);
    waitForClockState(LOW);
 
    // wait for mouse to switch modes
    while ((digitalRead(_clockPin) == LOW) || (digitalRead(_dataPin) == LOW))
        ;
    // put a hold on the incoming data
    low(_clockPin);
}

I2C event

I2C
//---------------------------------I2C Events-------------------------------//
void receiveEvent(int bytesReceived){
  int i=0;
  clearReceiveBuffer();
  while(Wire.available()){   
    receiveBuffer[i++] = Wire.read(); 
  }  
}
void requestEvent(){
  int memoryAddress = receiveBuffer[0];
  if (memoryAddress >= ARD_DATA )//&& memoryAddress <=ARD_DATA + NUM_OF_SENSORS)
  {
    uint8_t data[8];  // each sensor is 2 byte value
    char dir=0;   
    if(X<0) {dir|=0x01;xdata=abs(X);}else xdata=X; // dir&0x01==1 is mean X<0 else X>0
    if(Y<0) {dir|=0x02;ydata=abs(Y);}else ydata=Y; // dir&0x02==1 is mean Y<0 else Y>0
    if(W<0) {dir|=0x04;wdata=abs(W);}else wdata=W; // dir&0x04==1 is mean W<0 else W>0
    data[0]=highByte(dir);  //data[0] and data[1] to Determine the negative or positive value of X,Y,W.
    data[1]=lowByte(dir);  
    data[2]=highByte(xdata);//data[2] and data[3] absolute value of X axis 
    data[3]=lowByte(xdata);  
    data[4]=highByte(ydata); data[4] and data[5] absolute value of Y axis 
    data[5]=lowByte(ydata);  
    data[6]=highByte(wdata);
    data[7]=lowByte(wdata);  data[6] and data[7] absolute value of Wheel
    int startidx = memoryAddress-ARD_DATA;
    Wire.write(data+startidx,8);  //Send to end of buffer
  }
} 

5, Send data from an Arduino to LEGO NXT via I2C

Connection

Code

Read and dislay data

I2C
#pragma config(Sensor, S1,ard,sensorI2CCustom)
#include "common.h" // I2C lib
#include "settings.h"
ubyte 				I2CReply[17]  ;  //technically we should use tByteArray
ubyte			  	I2CRequest[17];
int xdata;
int ydata;
int wdata;
int datas;
// take two bytes and make an integer
int makeInt(ubyte highbyte,ubyte lowbyte){
	return (highbyte<<8) | lowbyte;
}
int makeInt(ubyte highbyte,ubyte lowbyte){
	return (highbyte<<8) | lowbyte;
}
//start at memoryAddress and return back replysize in bytes
int I2CArduino(tSensors link, ubyte memoryAddress,ubyte replysize) {
	memset(I2CRequest, 0, 17);
	memset(I2CReply, 0, 17);
 
	I2CRequest[0] = 2;    // Message size
	I2CRequest[1] = ARDUINO_I2C_ADDR; // I2C Address
	I2CRequest[2] = memoryAddress; // memory address
	if (!writeI2C(link,I2CRequest,I2CReply,replysize)){
		return -1;
	}
	return 0;
}
 
//===========================================================
task main () {
 
	nI2CRetries = 3;
	clearDebugStream();
	writeDebugStreamLine("Starting...");
	wait1Msec(500);
	while (true){
		if (I2CArduino(ard,ARD_DATA,8)){
			writeDebugStreamLine("ERROROR!!");
		}
		datas=makeInt(I2CReply[0],I2CReply[1]); // take two bytes for Determine the negative or positive value of X,Y,W. 
	        xdata=makeInt(I2CReply[2],I2CReply[3]); // take two bytes for X axis
		ydata=makeInt(I2CReply[4],I2CReply[5]); // take two bytes for Y axis
		wdata=makeInt(I2CReply[6],I2CReply[7]); // take two bytes for W axis
		if(datas&0x01) xdata=-xdata;// if (datas&0x01==1) X<0
		if(datas&0x02) ydata=-ydata;// if (datas&0x02==1) Y<0
		if(datas&0x04) wdata=-wdata;// if (datas&0x04==1) W<0
		nxtDisplayTextLine(1,"(%4d,%4d)",xdata,ydata);
		nxtDisplayTextLine(3,"%4d",wdata);
	}
}

reference

If you have any questions please contact to me via email [email protected].

lego_nxt_optical_sensor.1538515069.txt.gz · Last modified: 2018/10/02 14:17 by phamquyenanh