Pan-Tilt HAT
| ||
Overview
Demos for Raspberry Pi and Jetson Nano are provided
Version Description
Due to chip discontinuation, the ambient light sensor has been changed from TSL2581FN to TSL25911FN. If you are an existing customer and need to purchase new modules, please update your ambient light sensor program accordingly. No action is needed if you are not using this feature. The new PCB version is marked with silkscreen "Rev2.1". Please take note of this distinction.
Introduction
Specifications
- Operating voltage: 3.3V/5V
- Controller chip: PCA9685
- Logic level: 3.3V
- Communication interface: I2C
- Product size: 56.6X65(mm)
Controller
The controller for this product is the PCA9685, a 12-bit precision, 16-channel PWM wave output chip based on I2C bus communication. The board also features an onboard TSL2581 ambient light sensor, which assists the camera by detecting light intensity. It is also controlled via the I2C interface and does not occupy many interface pin resources.
Communication Protocol
As mentioned above, both the PCA9685 and TSL2581 use I2C communication, which employs one data line and one clock line. The I2C bus uses three types of signals during data transmission: Start Signal, Stop Signal, and Acknowledge Signal.

Start Signal: SDA transitions from high to low while SCL is high, indicating the start of data transmission.
Stop Signal: SDA transitions from low to high while SCL is high, indicating the end of data transmission.
Acknowledge Signal: After receiving 8 bits of data, the receiving IC sends a specific low-level pulse to the transmitting IC, confirming successful reception.
- I2C Write Data Sequence

First, the host (e.g., Raspberry Pi, hereafter referred to as the host) sends a Start Signal. It then sends an 8-bit data byte combining its 7-bit I2C address and the Write operation bit to the slave device (e.g., the TSL2581 sensor module, hereafter referred to as the slave). The slave responds with an Acknowledge signal. The host then sends the command register address to the slave, which acknowledges again. Next, the host sends the value for the command register, and the slave acknowledges once more. This process continues until the host sends a Stop Signal, concluding the I2C write operation.
- I2C Read Data Sequence

First, the host sends a Start Signal. It then sends an 8-bit data byte combining its 7-bit I2C address and the Write operation bit to the slave. The slave responds with an Acknowledge signal. The host sends the command register address, which the slave acknowledges. The host then sends a new Start Signal, followed by an 8-bit data byte combining its 7-bit address and the Read operation bit. The slave acknowledges this. The slave then sends the value from its register to the host. The host sends an Acknowledge signal in response. This concludes when the host sends a Stop Signal.
I2C Address
From the communication description above, both the PCA9685 and TSL2581 use I2C. Therefore, they require different I2C addresses to avoid communication conflicts.
- PCA9685

For details, see page 7 of the PCA9685 datasheet
- TSL2581

For details, see page 13 of the TSL2581 datasheet
Note: For our module, the I2C address pins of PCA9685 are set to A5=A4=A3=A2=A1=A0=0 by default, with its I2C address being 0x40. The I2C address pin of TSL2581 is left floating, with its I2C address being 0x39. If you are not using the Raspberry Pi driver (e.g., when using an STM32), you may need to append the R/W bit to the lower position.
Working with Raspberry Pi
Do not assemble the servos initially. Since the servo's initial angle is not at the starting position, direct assembly might cause the servo to jam during rotation. It is recommended to first test the servo's rotation range separately to prevent accidental damage. Please follow the tutorial steps in order.
Hardware Configuration
Enable I2C Interface
- Open the Raspberry Pi terminal and input the following command to enter the configuration interface:
sudo raspi-config Select Interacting Options ->I2C ->yes to start the I2C kernel driver
sudo reboot
Install Libraries
wiringpi
- Download and compile the source code
#Switch to home directory cd #Get library source code git clone https://github.com/WiringPi/WiringPi.git cd WiringPi #Compile the library. Note: Replace "3.x" with the actual version downloaded. ./build debian mv debian-template/wiringpi-3.x.deb . #Install the library. Similarly, replace "3.x" with the actual version. sudo apt install ./wiringpi-3.x.deb
Python Library
sudo apt-get install python3-smbus -y
Download Demo
wget https://files.waveshare.com/wiki/Pan-Tilt_HAT/Pan-Tilt_HAT_code.zip unzip Pan-Tilt_HAT_code.zip cd Pan-Tilt_HAT_code/RaspberryPi/
Debugging
| Brown Wire | GND |
| Red Wire | 5V |
| Orange Wire | S1/S0 |
Before running the test code, pay close attention to the mounting position of the tilt servo. Poor positioning may cause the servo to overheat and burn out. First, do not assemble the servo, ensuring it can rotate 360 degrees without obstruction. Connect the hardware: the pan servo to S1 and the tilt servo to S0. Then, navigate to the “test” folder within the program directory.
cd test make clean make sudo ./main
After running, all servos will rotate to 0 degrees (the servo rotation range is 0 to 180 degrees, i.e., the initial position). Then, cut the power and assemble, taking care not to rotate the tilt servo during assembly.
Assembly
The assembly diagram is as follows. The following images show the RPi Camera (I). Other cameras may have slight differences, which are explained separately later.




A: Pan Servo
B: Tilt Servo
How to Assemble Other Cameras
The module accessories include a separate package of M2 screws, containing 5 screws and 10 nuts. For all cameras, first attach the M2 screws to the camera, elevate the camera, then connect it to the acrylic plate, and finally secure the acrylic plate with screws.

RPi Camera V2

RPi Camera (E), RPi Camera (G), RPi Camera (F), RPi Camera (J), RPi Camera (M)

RPi Camera (H)

RPi NoIR Camera V2

RPi IR-CUT Camera (Since this camera's hole positions are non-standard, only two screws can be secured.)

Demo
Basic Demo
#Execute the following in the Pan-Tilt-HAT/RaspberryPi/ directory: #If using the ambient light sensor, run this: cd Light_Sensor/ #If using the pan-tilt mechanism, run this: cd Servo_Driver/
- BCM2835 demo (As system versions update, bcm2835 is no longer recommended. Please use wiringpi and python examples for testing.)
cd bcm2835 make clean make sudo ./main
- wiringpi demo
cd wiringpi make clean make sudo ./main
- Python demo
cd python sudo python main.py
Remote Control via BOTTLE
Bottle is a simple, efficient, WSGI-compliant micro web framework for Python. Using Bottle, web control can be quickly implemented. (Note: This example only supports Python 2).
Install the library:
sudo apt-get install python3-bottle -y cd Pan-Tilt-HAT/RaspberryPi/web_Python/ sudo python main.py
In the Google Chrome address bar (other browsers may have issues), enter the Raspberry Pi's IP address with port number 8001. The following page will be displayed. Click the buttons to control the device.

Supports control from both mobile phones and computers without needing an app.
Mobile Control:

Computer Control:

Jetson Nano
Install Libraries
Install Function Libraries
- Open the terminal and enter the following commands to install the required libraries.
sudo apt-get update sudo apt-get install python3-pip sudo pip3 install Jetson.GPIO sudo groupadd -f -r gpio sudo usermod -a -G gpio your_user_name sudo cp /opt/nvidia/jetson-gpio/etc/99-gpio.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules && sudo udevadm trigger
Note: Replace "your_user_name" with your actual username (e.g., waveshare).
- Install I2C
sudo apt-get install python-smbus
- Install image processing libraries:
sudo apt-get install python3-pil sudo apt-get install python3-numpy
Download Demo
sudo apt-get install p7zip wget https://files.waveshare.com/upload/9/96/Pan-Tilt_HAT_code.7z 7zr x Pan-Tilt_HAT_code.7z -r -o./Pan-Tilt_HAT_code sudo chmod 777 -R Pan-Tilt_HAT_code cd Pan-Tilt_HAT_code/JetsonNano/
Alternatively, you can download the project from our GitHub:
sudo git clone https://github.com/waveshare/Pan-Tilt-HAT cd Pan-Tilt-HAT/JetsonNano/
Basic Demonstration
#If using the ambient light sensor, run this: cd 1_Light_Sensor/ #If using the pan-tilt mechanism, run this: cd 2_Servo_Driver/
- Python demo
# python2 cd python2 sudo python main.py # python3 cd python3 sudo python3 main.py
Mobile Phone Camera Control
Camera Test
DISPLAY=:0.0 gst-launch-1.0 nvarguscamerasrc ! \'video/x-raw(memory:NVMM), width=1920, height=1080, format=(string)NV12, framerate=(fraction)30/1\' ! nvoverlaysink -e
Normally, the camera feed will be displayed on the screen. Press Ctrl + c to exit.
APP Download
Download the Android app:
https://files.waveshare.com/wiki/common/AlphaBot_LITE.apk
Pan-tilt Control
Run in the terminal:
cd 3_Pan-Tilt+CAM sudo python main.py

Initially, the program will retrieve the Jetson's IP address, which will be used later in the app.
Subsequently, the camera will activate and display its feed on the screen.
Mobile App Control: Open the app and click on "Wifi Control".
Enter the IP Address: 192.168.6.14
Enter the control interface. Only the four buttons on the right side are functional.

When you rotate the camera, the screen displays the camera feed in real-time.

Resources
Documents
Demos
Datasheets
FAQ
- It cannot achieve precise control; this is an entry-level product.
- Minor jitter is normal. It occurs when the desired rotation angle is smaller than the servo's minimum physical step angle. A current is maintained to hold the position, which can cause jitter.
- The control chip (PCA9685) has two I2C addresses on power-up: one configured by the onboard resistors (default 0x40), and another (0x70) derived from the ALLCALLADR register. Running the example code once will make you understand this register value. The other I2C address (0x39) belongs to the ambient light sensor.
- 1. Check if the servo wires are connected incorrectly.
- 2. Swap the connectors of the two servos to determine if it's a servo issue or a lack of output from one connector.
- 3. Test the servo rotation after removing all other accessories.
- 4. If you have another Raspberry Pi, test with it to see if the issue is with the Pi's pins.
- 5. Test with a fresh Raspberry Pi OS installation. The current system configuration might be causing the issue; test with a clean system.
Support
Technical Support
If you need technical support or have any feedback/review, please click the Submit Now button to submit a ticket, Our support team will check and reply to you within 1 to 2 working days. Please be patient as we make every effort to help you to resolve the issue.
Working Time: 9 AM - 6 PM GMT+8 (Monday to Friday)

