Assignment 2: Joystick Mouse Control

Microcontroller 1

Instructor: Reza Farashahi

Objective

The goal of this assignment is to interface an Arduino Uno with a Python script on your computer. You will read the X and Y coordinates from a joystick module using the Arduino's analog-to-digital converter (ADC). These coordinates will then be sent to your computer via the serial port. A Python script will read this serial data and use it to control the position of your mouse pointer on the screen.

This project will teach you about:

Hardware & Software Requirements

Part 1: The Arduino Side - Reading and Sending Data

First, we need to wire the joystick to the Arduino and write a sketch to read its values and send them over the serial port.

Circuit Diagram

Connect your joystick module to the Arduino Uno as shown below. Joystick modules typically have 5 pins:

Fritzing diagram showing joystick connected to Arduino Uno. GND to GND, 5V to 5V, VRx to A0, VRy to A1.

Arduino Sketch

The Arduino sketch should perform these steps in a loop:

  1. Read the analog value from the X-axis pin (A0).
  2. Read the analog value from the Y-axis pin (A1).
  3. Format these two values into a single string, separated by a comma (e.g., "512,510").
  4. Send this string over the serial port using Serial.println().
  5. Add a small delay to avoid flooding the serial port with too much data.

Here is a starter code snippet. You will need to complete it.

// Define the analog pins connected to the joystick
#define VRX_PIN A0 // Joystick X-axis
#define VRY_PIN A1 // Joystick Y-axis

void setup() {
  // Initialize serial communication at a 9600 bits-per-second baud rate.
  // This rate must match the rate used in your Python script.
  Serial.begin(9600);
}

void loop() {
  // Read the analog values from the joystick
  int xValue = analogRead(VRX_PIN);
  int yValue = analogRead(VRY_PIN);

  // Print the values to the serial port in a "x,y" format
  Serial.print(xValue);
  Serial.print(",");
  Serial.println(yValue); // println adds a newline character at the end

  // A small delay to make the communication stable
  delay(50); 
}

Upload this code to your Arduino Uno. You can check if it's working by opening the Serial Monitor in the Arduino IDE (Tools > Serial Monitor). Make sure the baud rate is set to 9600. You should see a stream of numbers like 512,511 that change as you move the joystick.

Part 2: The Python Side - Receiving Data and Controlling the Mouse

Now we will write a Python script to read the data from the Arduino and move the mouse.

Python Environment Setup

You will need two Python libraries: pyserial to read from the serial port and pyautogui to control the mouse. Open your terminal or command prompt and install them using pip:

pip install pyserial
pip install pyautogui

Test Function: Reading from the Serial Port

How to Test Your Serial Connection

Before trying to control the mouse, it's very important to confirm that Python can receive data from your Arduino. Use the following test script. This script will simply print whatever it receives from the serial port to your console.

Important: You must find your Arduino's COM port name. On Windows, it looks like COM3, COM4, etc. On macOS or Linux, it's something like /dev/tty.usbmodem14101 or /dev/ttyACM0. You can find this in the Arduino IDE under Tools > Port.

# test_serial.py
import serial
import time

# --- IMPORTANT ---
# CHANGE 'COM3' to your Arduino's port.
# You can find this in the Arduino IDE under Tools > Port.
# For Mac/Linux, it will be something like '/dev/tty.usbmodemXXXX'
ARDUINO_PORT = 'COM3' 
BAUD_RATE = 9600

try:
    # Establish a serial connection
    arduino = serial.Serial(ARDUINO_PORT, BAUD_RATE, timeout=1)
    time.sleep(2) # Wait for the connection to establish

    print(f"Connected to Arduino on {ARDUINO_PORT}. Reading data...")
    print("Move your joystick to see the values change.")
    print("Press Ctrl+C to exit.")

    while True:
        # Read one line of data from the serial port
        data = arduino.readline()

        # Check if any data was received
        if data:
            # Decode the bytes into a string and remove leading/trailing whitespace
            decoded_data = data.decode('utf-8').strip()
            print(f"Received: {decoded_data}")

except serial.SerialException as e:
    print(f"Error: Could not open port {ARDUINO_PORT}. {e}")
except KeyboardInterrupt:
    print("\nProgram terminated by user.")
finally:
    if 'arduino' in locals() and arduino.is_open:
        arduino.close()
        print("Serial port closed.")

Run this script from your terminal: python test_serial.py. If everything is set up correctly, you should see the same coordinate stream that you saw in the Arduino Serial Monitor.

Troubleshooting

Main Task: Controlling the Mouse

Once your test script works, you can move on to the main task. You need to modify the script to:

  1. Parse the incoming string (e.g., "512,510") to get separate X and Y integer values.
  2. Get the size of your computer screen.
  3. Map the joystick's analog values (0 to 1023) to your screen's pixel coordinates (e.g., 0 to 1920 for width, 0 to 1080 for height).
  4. Use the mapped coordinates to move the mouse pointer using pyautogui.moveTo().

Hints for the Main Script

Here is a skeleton to guide you. You need to fill in the logic inside the `while` loop.

# joystick_mouse.py
import serial
import pyautogui
import time

# --- Configuration ---
ARDUINO_PORT = 'COM3' # CHANGE THIS to your Arduino's port
BAUD_RATE = 9600

# Get screen dimensions
screenWidth, screenHeight = pyautogui.size()
print(f"Screen size: {screenWidth} x {screenHeight}")

# Establish serial connection
arduino = serial.Serial(ARDUINO_PORT, BAUD_RATE)
time.sleep(2) # Wait for connection

print("Starting mouse control. Move the joystick.")
print("Press Ctrl+C to exit.")

try:
    while True:
        # 1. Read a line from the Arduino
        data = arduino.readline().decode('utf-8').strip()

        # 2. Make sure the data is not empty
        if data:
            try:
                # 3. Split the string into two parts and convert to integers
                x_str, y_str = data.split(',')
                x_val = int(x_str)
                y_val = int(y_str)

                # 4. Map the joystick values (0-1023) to screen coordinates
                # The joystick's X-axis might be inverted, so we map 1023-0 instead of 0-1023.
                # You might need to adjust this based on your joystick's orientation.
                mouseX = (x_val * screenWidth) / 1023
                mouseY = (y_val * screenHeight) / 1023
                
                # 5. Move the mouse to the new coordinates
                pyautogui.moveTo(mouseX, mouseY)

            except (ValueError, IndexError):
                # Handle cases where the data is not in the expected "x,y" format
                print(f"Warning: Received malformed data: {data}")
                continue

except KeyboardInterrupt:
    print("\nProgram terminated.")
finally:
    arduino.close()

Submission

Please submit the following files in a single ZIP archive named YourName_Assignment2.zip:

  1. Your final Arduino sketch file (.ino).
  2. Your final Python script file (.py).
  3. A short video (max 30 seconds) demonstrating your project in action. Show the joystick moving and the mouse pointer responding on the screen.

Grading Rubric

Criteria Points Description
Arduino Code Correctness 30 Sketch correctly reads both X and Y axes and sends them over serial in the specified format. Code is clean and commented.
Python Code Correctness 40 Script successfully reads from the serial port, parses the data, maps the values correctly, and controls the mouse. Handles potential errors.
Functionality & Demonstration 20 The project works as intended. The mouse movement is smooth and corresponds to the joystick movement, as shown in the video.
Code Style and Comments 10 Both Arduino and Python code are well-formatted, readable, and include comments explaining the logic.
Total 100