In this project, we explored the capabilities of the ADNS-5090 optical mouse sensor. From capturing image data to tracking motion in real-time, this versatile sensor offers a wealth of possibilities. Here's a detailed account of how we got it all working, with Arduino and Python.
- Arduino Uno
- ADNS-5090 Optical Mouse Sensor
- Breadboard and Jumper Wires
- Computer with Arduino IDE and Python
Begin by connecting the ADNS-5090 sensor to the Arduino Uno. Ensure all connections are secure, following this pin configuration:
ADNS-5090 Pin | Arduino Uno Pin | Notes |
---|---|---|
MISO | 12 (MISO) | SPI data output |
MOSI | 11 (MOSI) | SPI data input |
SCLK | 13 (SCK) | SPI clock |
NCS | 10 (CS) | Chip Select |
VDD | 3.3V | Power supply |
GND | GND | Ground |
First, we need to initialize the sensor. The Arduino sketch below does this by setting up SPI communication and initializing the ADNS-5090:
#include <SPI.h>
#define CS_PIN 10
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for the Serial to initialize
Serial.println("Initializing...");
pinMode(CS_PIN, OUTPUT);
digitalWrite(CS_PIN, HIGH); // Ensure CS is high
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV16); // Set SPI clock speed
SPI.setDataMode(SPI_MODE3); // Set SPI mode
// Initialize the sensor
digitalWrite(CS_PIN, LOW);
delay(100); // Hold reset low longer
writeRegister(0x00, 0x80); // Reset command
delay(100);
writeRegister(0x00, 0x00); // End reset
digitalWrite(CS_PIN, HIGH);
delay(1000); // Extended delay for sensor initialization
Serial.println("Sensor initialized");
}
void loop() {
// Your main code here
}
byte readRegister(byte reg) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(reg);
byte value = SPI.transfer(0x00);
digitalWrite(CS_PIN, HIGH);
return value;
}
void writeRegister(byte reg, byte value) {
digitalWrite(CS_PIN, LOW);
SPI.transfer(reg | 0x80); // Set MSB for write operation
SPI.transfer(value);
digitalWrite(CS_PIN, HIGH);
}
Next, we set up the sensor to capture image data. Here’s how we read pixel values from the sensor:
#include <SPI.h>
#define CS_PIN 10
#define PIXEL_REGISTER 0x0b // Register for pixel data
#define IMAGE_WIDTH 19
#define IMAGE_HEIGHT 19
void loop() {
byte image[IMAGE_HEIGHT][IMAGE_WIDTH];
// Capture image data
Serial.println("Reading pixel data:");
for (int i = 0; i < IMAGE_HEIGHT; i++) {
for (int j = 0; j < IMAGE_WIDTH; j++) {
byte pixelValue = readRegister(PIXEL_REGISTER);
if (pixelValue & 0x80) { // Check if pixel data is valid
byte pixelData = pixelValue & 0x7F; // Mask out PG_VALID bit
image[i][j] = pixelData;
} else {
image[i][j] = 0; // Mark invalid pixel as 0
}
writeRegister(PIXEL_REGISTER, 0x00); // Reset the grabber to origin
}
}
// Print image data
for (int i = 0; i < IMAGE_HEIGHT; i++) {
for (int j = 0; j < IMAGE_WIDTH; j++) {
Serial.print(image[i][j]);
Serial.print("\t"); // Print with tab space
}
Serial.println(); // New line after each row
}
delay(5000); // Capture image every 5 seconds
}
For real-time motion tracking, we read the motion data (dx, dy) and plot it using Python and matplotlib
. Update your Arduino code to output motion data:
#include <SPI.h>
#define CS_PIN 10
#define MOTION_REGISTER 0x02
#define DELTA_X_REGISTER 0x03
#define DELTA_Y_REGISTER 0x04
void loop() {
byte motion = readRegister(MOTION_REGISTER); // Read motion register
if (motion & 0x80) { // Check if there is movement
int dx = (int8_t)readRegister(DELTA_X_REGISTER); // Read delta X
int dy = (int8_t)readRegister(DELTA_Y_REGISTER); // Read delta Y
Serial.print(dx);
Serial.print(",");
Serial.println(dy);
}
delay(100); // Short delay between readings
}
Using Python, we can plot the motion data in real-time. Here's the Python script:
import serial
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# Set up the serial connection (adjust the port and baud rate as needed)
ser = serial.Serial('COM3', 115200) # Replace 'COM3' with your port
# Initialize the position of the point
current_x = 0
current_y = 0
fig, ax = plt.subplots()
point, = ax.plot([], [], 'ro')
def init():
ax.set_xlim(-100, 100) # Adjust limits based on expected motion range
ax.set_ylim(-100, 100)
return point,
def update(frame):
global current_x, current_y
if ser.in_waiting > 0:
data = ser.readline().decode('utf-8').strip()
if ',' in data: # Check if the line contains motion data
try:
dx, dy = map(int, data.split(','))
current_x += dx
current_y += dy
# Update the point's position
point.set_data(current_x, current_y)
# Update plot limits if necessary
ax.set_xlim(current_x - 100, current_x + 100)
ax.set_ylim(current_y - 100, current_y + 100)
except ValueError:
pass # Skip lines that can't be parsed
return point, # Return a sequence of Artist objects
ani = FuncAnimation(fig, update, init_func=init, blit=True)
plt.show()
This project demonstrates how to leverage the ADNS-5090 sensor for capturing images and tracking motion. Whether for educational purposes or prototyping, the ADNS-5090 offers a versatile tool for exploring sensor technology.
Feel free to leave comments or reach out if you have any questions or suggestions. Happy tinkering!
I hope this helps! You can expand upon each section with more details or personal insights to make it even more engaging. Let me know if there's anything else you'd like to add or change!