1 - Introduction to the PinPong Library

UNIHIKER is equipped with a microcontroller coprocessor, whose duty is to control the onboard components and GPIO interfaces. In order to achieve hardware control, we utilize the PinPong library in Python to communicate with the coprocessor and write Python code to control the hardware.

Introduction

The PinPong library is a collection of Python code for controlling open-source hardware mainboards. It is based on the Firmata protocol and compatible with MicroPython syntax, allowing you to quickly and easily control open-source hardware using Python within just five minutes.

With the assistance of the PinPong library, you can directly program various common open-source hardware using Python code. The underlying principle involves flashing a specific firmware onto the open-source hardware, enabling it to communicate with the computer via a serial port and execute various commands.

The design of the PinPong library aims to free developers from the constraints of complex hardware models during the development process, allowing them to focus on software implementation. Even if the initial development is done with Arduino and later switched to a different control board, such as Controllino, a simple modification of the hardware parameters enables the program to run smoothly, achieving "write once, run anywhere" functionality.

2 - Installing the PinPong Library

Note: The PinPong library is already integrated into the factory firmware of UNIHIKER, so this step can be skipped.

The PinPong library can be installed and updated using the pip tool.

Installation:

pip install pinpong

Update:

pip install -U pinpong

================

3 - Importing the PinPong Library

  • As the PinPong library supports various types of microcontroller boards and open-source hardware, it is divided into three packages: "board", "extension", and "libs". The "board" package comprises the commonly used libraries and functions supported by microcontroller boards, the "extension" package contains the customized libraries related to specific microcontroller boards, while the "libs" package includes expansion libraries for other sensors.
  • As the PinPong library aims to support multiple microcontrollers, corresponding objects can be generated based on specified board types and port numbers when using the library. However, as the coprocessor and port numbers on the UNIHIKER are already fixed, object initialization can be performed directly when using the UNIHIKER , without the need to specify these parameters.
from pinpong.board import xxx   # Importing the xxx library from the board package
from pinpong.libs.xxx    # Importing the xxx library from the libs package
from pinpong.extension.xxx    # Importing the xxx module from the extension package

Board().begin()    # Initializing the Board: connecting the coprocessor and checking firmware. If the firmware is empty or the version is incorrect, automatic burning will be performed.

Note: Please replace xxx with the actual names of the libraries or modules you are using.

----------------

4 - UNIHIKER Onboard Features Usage Instructions

|- 4.1-L(LED)

On the back of the UNIHIKER, there is a blue LED light marked "L" which users can control through programming.
The onboard LED labeled as 'L' is connected to the P25 interface of UNIHIKER, so controlling the P25 pin allows for control of the onboard LED.

  • **Syntax: **Pin(Pin.P25, Pin.OUT).write_digital
  • **Return: **None
  • **Input: **1 High level, 0 low level
  • Python Sample Program
# -*- coding: UTF-8 -*-
#This is a sample code using the PinPong Library to control the on and off of an LED and print corresponding messages when the LED is on/off. Comments are added after each line of the code to improve its readability.

import time
from pinpong.board import Board, Pin

Board().begin() # Initialize the UNIHIKER

led = Pin(Pin.P25, Pin.OUT) # Set Pin P25 as an output pin for the LED

while True:
   
    led.write_digital(1) # Turn on the LED by setting the pin value to high
    print("The LED light is on") # Display a message indicating that the LED light is on 
    time.sleep(1)  # Pause the program for 1 second
    led.write_digital(0) # Turn off the LED by setting the pin value to low
    print("The LED light is off")  # Display a message indicating that the LED light is off
    time.sleep(1) # Pause the program for 1 second
  • Mind+ Sample Program

|- 4.2-Button A and Button B

Note:On the microcontrollers of UNIHIKER, there are three buttons: Home, A, and B. Among them, the Home button is exclusively designated for the homepage menu, while the A and B buttons are available for user invocation. It should be noted that due to the simultaneous mapping of the A and B buttons to the AB button on the keyboard, apart from utilizing PinPong for invocation, one can also employ keyboard events from the UNIHIKER library or other libraries such as Pygame and OpenCV that enable keyboard input retrieval for invocation purposes.

In the Pinpong library, there are two ways to invoke buttons. The first is the query method, which directly reads the button state or performs related operations. The second is the callback method, which defines callback functions to handle interrupt events.

  • Query-based Invocation :
    • **Syntax: **button_a.is_pressed() button_b.is_pressed()
    • **Return:**When the button is pressed, True is returned; False is returned when the button is not pressed.
    • **Input:**None
    • Python Sample Program:
# -*- coding: utf-8 -*-
from pinpong.board import *
from pinpong.extension.unihiker import *

Board().begin() # Initialize the UNIHIKER

while True:
    # Check if button A is pressed
    if button_a.is_pressed() == True: 
        print("Press button A")

    # Check if button B is pressed
    if button_b.is_pressed() == True: 
        print("Press button B")

  • Mind+ Sample Program

  • Callback Invocation :
    • Syntax: button_a.irq(trigger=trigger mode, handler=callback function) button_b.irq(trigger=trigger mode, handler=callback function)
    • Return: None
    • Input:
      • Trigger: trigger mode, which has three modes: rising edge(Pin.IRQ_RISING), falling edge(Pin.IRQ_FALLING), and both edges(Pin.IRQ_RISING+Pin.IRQ_FALLING).
    • Python Sample Program:
# -*- coding: utf-8 -*-
from pinpong.board import *
from pinpong.extension.unihiker import *
import time

Board().begin()  # Initialize the UNIHIKER

def btn_a_rasing_handler(pin):  # Interrupt event callback function for button A rising edge
    print("Press button A")

def btn_b_falling_handler(pin):  # Interrupt event callback function for button B falling edge
    print("Release button B")

# Register interrupt event handlers for button A and button B
button_a.irq(trigger=Pin.IRQ_RISING, handler=btn_a_rasing_handler)  # Trigger on rising edge
button_b.irq(trigger=Pin.IRQ_FALLING, handler=btn_b_falling_handler)  # Trigger on falling edge

while True:
    time.sleep(1)  # Wait to prevent the program from exiting

    

|- 4.3-Light Sensor

The UNIHIKER microcontrollers has integrated a Light Sensor, allowing for the acquisition of ambient light intensity.

Note: The ambient light intensity values output by the light sensor are of an analog values, ranging from 0-4095, and are not expressed in lux units.

  • Syntax: light.read() ( Note: In the circuitry of UNIHIKER, the photovoltaic sensor is directly connected to the P29 interface, making it possible to read its value through the ADC input method.)
  • Return: The range of the ambient light intensity values is from 0 to 4095.
  • Input: None
  • Python Sample Program:
# -*- coding: UTF-8 -*-
import time
from pinpong.board import *
from pinpong.extension.unihiker import *

Board().begin()  # Initialize the UNIHIKER

while True:
    light_value = light.read()  # Read the ambient light intensity
    print("Ambient light intensity: %d" % (light_value))  # Print the ambient light intensity to the terminal
    time.sleep(0.1)  # Wait for 0.1 seconds to maintain the state

  • Mind+ Sample Program:

|- 4.4-Accelerometer and Gyroscope

The UNIHIKER's back panel is equipped with a 6-axis accelerometer-gyroscope sensor, capable of reading the X, Y, and Z values of acceleration individually, as well as the total strength in X, Y, and Z directions, and the X, Y, and Z values of the gyroscope.

  • Syntax:
    • Accelerometeraccelerometer.get_x() accelerometer.get_y() accelerometer.get_z() accelerometer.get_x()
    • Gyroscope:gyroscope.get_x() gyroscope.get_y() gyroscope.get_z()
  • Return: Accelerometer values and gyroscope values.
  • Input: None
  • Python Sample Program:
# -*- coding: utf-8 -*-
import time
from pinpong.board import *
from pinpong.extension.unihiker import *

Board().begin()  # Initialize the UNIHIKER

while True:
    print(accelerometer.get_x())  # Read the value of acceleration in the X-axis
    print(accelerometer.get_y())  # Read the value of acceleration in the Y-axis
    print(accelerometer.get_z())  # Read the value of acceleration in the Z-axis
    print(accelerometer.get_strength())  # Read the total strength of acceleration (combination of X, Y, and Z axes)
    print(gyroscope.get_x())  # Read the value of gyroscope in the X-axis
    print(gyroscope.get_y())  # Read the value of gyroscope in the Y-axis
    print(gyroscope.get_z())  # Read the value of gyroscope in the Z-axis
    print("------------------")
    time.sleep(1)

  • Mind+ Sample Program:

|- 4.5-Buzzer

The UNIHIKER main controllers is equipped with an integrated buzzer, capable of emitting pre-set tones.

  • Python Sample Program:
# -*- coding: utf-8 -*-
import time
from pinpong.board import Board, Pin
from pinpong.extension.unihiker import *

Board().begin()  # Initialize the UNIHIKER

# Music: DADADADUM ENTERTAINER PRELUDE ODE NYAN RINGTONE FUNK BLUES BIRTHDAY WEDDING FUNERAL PUNCHLINE
# Music: BADDY CHASE BA_DING WAWAWAWAA JUMP_UP JUMP_DOWN POWER_UP POWER_DOWN
# Play mode: Once (play once) Forever (play continuously) OnceInBackground (play once in the background) ForeverInBackground (play continuously in the background)
buzzer.play(buzzer.DADADADUM, buzzer.Once)  # Play music once
# buzzer.set_tempo(4, 60)  # Set the number of notes per beat and the beats per minute
buzzer.pitch(494, 4)  # Play a pitch/note
# buzzer.pitch(494)  # Play a pitch/note in the background
# time.sleep(10)
# buzzer.stop()  # Stop playing in the background
# buzzer.redirect(Pin.P0)  # Redirect the buzzer to a specific pin, only supports PWM pins
# buzzer.play(buzzer.ENTERTAINER, buzzer.ForeverInBackground)  # Play music continuously in the background
while True:
    time.sleep(1)  # Wait for 1 second to maintain the state

  • Mind+ Sample Program:

|- 4.6-Environmental sound level

The microphone on the UNIHIKER is not a regular sound sensor. It possesses the ability to directly record audio for voice recognition, and that is why it is connected to the CPU. Therefore, to obtain the environmental sound level, it is recommended to utilize the Audio class from the UNIHIKER library instead of Pinpong library.

Please click to view:unihiker library

  • Python Sample Program:
# -*- coding: utf-8 -*-
from unihiker import Audio
import time

audio = Audio()  # Instantiate the Audio object

while True:
    value = audio.sound_level()  # Get the ambient volume level
    print("Ambient volume = %d" % (value))
    time.sleep(0.1)  # Wait for 0.1 seconds

----------------

5 - A Guide to Basic Usage of GPIO

The operation of UNIHIKER pins follows the same syntax as that of PinPong.

|- 5.1-Digital Output

All pins of UNIHIKER allow for digital output, with a voltage level of 3.3V.

  • Python Sample Program:
# -*- coding: UTF-8 -*-
# Experiment Effect: Control an external LED to blink once every second
# Wiring: Connect an LED to the UNIHIKER P21 pin
import time
from pinpong.board import Board, Pin

Board().begin()  # Initialize the UNIHIKER

led = Pin(Pin.P21, Pin.OUT)  # Initialize the pin as an output pin

while True:
    # led.value(1)  # Set the pin output to high level - Method 1
    led.write_digital(1)  # Set the pin output to high level - Method 2
    print("1")  # Print message to the terminal
    time.sleep(1)  # Wait for 1 second to maintain the state

    # led.value(0)  # Set the pin output to low level - Method 1
    led.write_digital(0)  # Set the pin output to low level - Method 2
    print("0")  # Print message to the terminal
    time.sleep(1)  # Wait for 1 second to maintain the state

  • Mind+ Sample Program:

|- 5.2-Digital Input

UNIHIKER's pins are all capable of digital input, with a voltage level of 3.3V.

  • Python Sample Program:
# -*- coding: UTF-8 -*-
# Experiment Effect: Use the button to toggle the state of the blue LED labeled "L" on the back of the UNIHIKER.
# Wiring: Connect a button module to the UNIHIKER P23 interface
import time
from pinpong.board import Board, Pin

Board().begin()  # Initialize the UNIHIKER

btn = Pin(Pin.P23, Pin.IN)  # Initialize the pin as an input pin
led = Pin(Pin.P21, Pin.OUT)  # Initialize the LED pin as an output pin

while True:
    # v = btn.value()  # Read the pin level - Method 1
    v = btn.read_digital()  # Read the pin level - Method 2
    print(v)  # Print the read pin level to the terminal
    # led.value(v)  # Set the LED pin according to the button state - Method 1
    led.write_digital(v)  # Set the LED pin according to the button state - Method 2
    time.sleep(0.1)  # Wait for 0.1 seconds

  • Mind+ Sample Program:

|- 5.3-Analog Input(ADC)

UNIHIKER supports 8 channels of 12-bit high-precision analog input ADC, corresponding to the following pins: P0, P1, P2, P3, P4, P10, P21 and P22.

  • Python Sample Program:
# -*- coding: UTF-8 -*-
# Experiment Effect: Print the analog value of the UNIHIKER P21 pin
# Wiring: Connect a potentiometer module to the UNIHIKER P21 pin
import time
from unihiker.board import Board, Pin

Board().begin()  # Initialize the UNIHIKER
# ADC analog input pins supported: P0 P1 P2 P3 P4 P10 P21 P22
# adc21 = ADC(Pin(Pin.P21))  # Use Pin object with ADC to enable analog input - Method 1
adc21 = Pin(Pin.P21, Pin.ANALOG)  # Initialize the pin as an analog input - Method 2

while True:
    # v = adc21.read()  # Read the analog signal value from pin A0 - Method 1
    v = adc21.read_analog()  # Read the analog signal value from pin A0 - Method 2
    print("P21 =", v)
    time.sleep(0.5)  # Wait for 0.5 seconds

  • Mind+ Sample Program:

|- 5.2-Analog Output(PWM)

UNIHIKER supports 8 channels of 10-bit PWM output, corresponding to the following pins: P0, P2, P3, P10, P16, P21, P22 and P23.

Note: Note that P8 and P2 share one PWM channel, while P9 and P10 share another PWM channel. Therefore, when P8 or P9 is using PWM, P2 and P10 cannot be used. Additionally, please note that P8 and P9 are grouped together, as are P2 and P10. Only one group can be used at a time and they cannot be mixed. For example, if P8 or P9 is outputting PWM, then P2 or P10 cannot output PWM signals.

  • Python Sample Program:
# -*- coding: UTF-8 -*-
# Experiment Effect: PWM output experiment, control LED brightness variation
# Wiring: Connect an LED to the UNIHIKER P21 pin
import time
from pinpong.board import Board, Pin

Board().begin()  # Initialize the UNIHIKER board

# PWM analog output pins supported: P0  P2  P3  P10  P16  P21  P22  P23
# pwm21 = PWM(Pin(Pin.P21))  # Initialize the pin as a PWM output - Method 1
pwm21 = Pin(Pin.P21, Pin.PWM)  # Initialize the pin as a PWM output - Method 2

while True:
    for i in range(1023):
        print(i)
        # pwm21.duty(i)  # Set the duty cycle of the PWM output - Method 1
        pwm21.write_analog(i)  # Set the duty cycle of the PWM output - Method 2
        time.sleep(0.05)  # Wait for 0.05 seconds

  • Mind+ Sample Program:

----------------

6 - Advanced Features

|- 6.1-Serial Port(UART)

Within the golden finger interface of UNIHIKER, there exists support for a solitary hardware serial port, enabling its utilization in conjunction with expansion boards compatible with micro:bit.
Note:Software serial port is not supported.

Note:On the UNIHIKER main control board, there is a USB interface available. As UNIHIKER is equipped with built-in ch340, cp2102, and pl2303 serial port drivers, you can directly use a USB to TTL adapter to connect serial devices and perform communication using the pyserial library.[Examples]

# -*- coding: utf-8 -*-
import time
from pinpong.board import Board, UART

Board("UNIHIKER").begin()  # Initialize the UNIHIKER board. Select the board type, if not specified, it will be automatically detected.

#hardware UART 1 : P0-RX    P3-TX
uart1 = UART(bus_num=0)   # Initialize UART (Hardware Serial 1)

# Initialize UART: `baud_rate` for baud rate, `bits` for the number of data bits (8/9), `parity` for parity check (0 none/1 odd/2 even), `stop` for stop bits (1/2).
uart1.init(baud_rate=115200,bits=8,parity=0,stop=1)  

buf = [0x00, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07]

# Close hardware UART 1
# uart1.deinit() 

# Get the number of bytes available to read from UART
# uart1.any() 

# Write data to the UART. buf is a list of bytes.
# uart1.write(buf)

# Read characters from the UART. Returns None or a list of bytes.
# uart1.read(n)

# Read a line until a newline character is received. Reads until newline or None if timeout occurs.
# buf = uart1.readline()

# Read bytes into buf. If nbytes is specified, read at most that many bytes. Otherwise, read at most len(buf) bytes.
# uart1.readinto(buf, nbytes)

while True:
    uart1.write(buf)  # Write data to UART
    while uart1.any() >0:
        print(uart1.read(1))
    time.sleep(1)

|- 6.2-SPI

On the UNIHIKER's golden finger interface, there is support for two SPI interfaces, which can be used in conjunction with micro:bit compatible expansion boards.

import time
from pinpong.board import Board, Pin, SPI

Board("UNIHIKER").begin()  # Initialize the UNIHIKER board. Select the board type, if not specified, it will be automatically detected.

# 0 represents SPI0 (P1 SCK, P10 MISO, P2 MOSI), 1 represents SPI1 (P13 SCK, P14 MISO, P15 MOSI)
# cs is the chip select pin, can only be used as master
spi0 = SPI(0, cs=Pin.P3)

w_buf = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]

while True:
    # r_buf = spi0.read(1)    # Read 1 bytes from the slave
    # print(r_buf)
    # spi0.write(0x88)        # Send a single byte using SPI0
    spi0.write(w_buf)         # Send the contents of w_buf using SPI0
    time.sleep(1)

----------------

7 - Examples of Sensor Usage

Looking to utilize the sensors supported by the pinpong library on UNIHIKER? Simply make the necessary modifications to the corresponding pin codes.

|- DHT11 Temperature & Humidity Sensor

If the sensor being used is of the digital signal type, then any pin on UNIHIKER can be chosen. The usage method is as follows: Insert the "Blank board pin" or "Read digital pin" pin block from the UNIHIKER library into the corresponding sensor pin object.

Note:As the UNIHIKER pin control blocks automatically performs initialization operations by default, there is no need for a separate pinpong initialization block.


|- Servo

If the actuator you are using requires PWM signal control, you need to select the pins marked with "~". Here is the usage method: insert the "Blank board pin ~A" pin block from the UNIHIKER library into the corresponding actuator pin object.

Note: As the UNIHIKER pin control blocks automatically performs initialization operations by default, there is no need for a separate pinpong initialization block.

Note: The onboard interface of UNIHIKER is a PH2.0 interface, and the regular servo cable is a 2.54mm DuPont header. Therefore, you can use a 3 Pin PH2.0 to DuPont Male Connector Digital Cablefor the connection.But if you need to use a large servo, since the current may be too large, you should use an expansion board to connect it.


|- I2C Digital Wattmeter

If an I2C sensor is being used, it is necessary to incorporate the initialization block of pinpong.

Note: Since the building blocks from the UNIHIKER library are not utilized, it is necessary to perform separate initialization.

|- WS2812 RGB LED Strip

Insert the "Blank board pin" pin block from the UNIHIKER library into the corresponding sensor pin object. By setting the display color, you can either illuminate or turn off the RGB LED strip. For example, setting the display color to blue will make the RGB LED strip shine in blue, while setting it to black will turn off the RGB LED strip.

Note: Only one LED strip can be used.
Note: As the UNIHIKER pin control blocks automatically performs initialization operations by default, there is no need for a separate pinpong initialization block. Note: If you want to provide external power to the WS2812, there are a few important points to consider: supply a voltage of 3.3V and ensure a common ground.


For more example programs, you can view unihiker’s pinpong directory: /usr/local/lib/python3.7/dist-packages/pinpong/examples/

----------------

7 - FAQ

If you encounter any issues and cannot find a solution, please email us at unihiker@dfrobot.com, or scan the QR code below to join the UNIHIKER communication channel.

img