Orange Pi RV2

The Orange Pi RV2 is a quad-core RISC-V single board computer with up to 8 GB of RAM and full Linux support. It fills the role in the Rovari ecosystem that the Raspberry Pi fills in the ARM world: a general purpose Linux box with GPIO headers, camera and display connectors, USB, Ethernet, WiFi, and HDMI output.

Where the CH32V003 teaches you bare metal embedded programming, the Orange Pi RV2 is for applications that need a full operating system: edge computing, IoT gateways, home automation, web servers, and containerized services. The 40-pin GPIO header is electrically compatible with Raspberry Pi HATs, so most existing add-on boards work without modification.

Specifications

ComponentDetail
ProcessorQuad-core RISC-V @ 1.5 GHz
RAM2 GB / 4 GB / 8 GB LPDDR4X
StorageMicroSD slot, optional eMMC socket
VideoHDMI 2.0 (4K @ 60 Hz)
USB2x USB 3.0, 1x USB 2.0 OTG
NetworkGigabit Ethernet, WiFi 5, Bluetooth 5.0
GPIO40-pin header (Raspberry Pi compatible)
DisplayDSI connector for LCD panels
CameraCSI connector for camera modules
Power5V / 3A via USB-C or GPIO header
Temperature0°C to 70°C
Dimensions85 mm x 56 mm

Setup

What you need

  • Orange Pi RV2 board
  • MicroSD card (16 GB or larger, Class 10)
  • 5V / 3A USB-C power supply
  • HDMI cable and monitor (optional for headless setup)
  • USB keyboard and mouse (for initial configuration)
  • Ethernet cable or WiFi credentials

Flash the image

Download the latest Ubuntu or Debian image for Orange Pi RV2 from the official Orange Pi website. Write it to your SD card using Balena Etcher or dd:

# Balena Etcher: select image, select SD card, click Flash

# Or using dd on Linux
sudo dd if=ubuntu-orangepi-rv2.img of=/dev/sdX bs=4M status=progress
sudo sync

First boot

  • Insert the SD card into the Orange Pi RV2
  • Connect HDMI, keyboard, and mouse
  • Connect power (the board boots automatically)
  • Wait for initial setup to complete (two to three minutes on first boot)

Default credentials: Username orangepi, password orangepi. Change these immediately after first login.

Linux Configuration

System update

After first boot, update everything and install build tools:

sudo apt update
sudo apt upgrade -y
sudo apt install build-essential git python3-pip -y

System settings

The built-in configuration tool handles filesystem expansion, hostname, timezone, and service management:

sudo orangepi-config

Use this to expand the filesystem to fill the entire SD card, set your timezone, and configure the keyboard layout.

Networking

Wired Ethernet

Ethernet works out of the box with DHCP. Verify your connection:

ip addr show
ping -c 4 google.com
hostname -I

Static IP

Edit the netplan configuration to assign a fixed address:

/etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      addresses:
        - 192.168.1.100/24
      gateway4: 192.168.1.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4
sudo netplan apply

WiFi

Connect using NetworkManager from the command line:

nmcli dev wifi list
nmcli dev wifi connect "YourSSID" password "YourPassword"
nmcli connection show

Hidden networks: nmcli dev wifi connect "SSID" password "pass" hidden yes

SSH

Enable SSH for headless access:

sudo apt install openssh-server -y
sudo systemctl enable ssh
sudo systemctl start ssh

Connect from another machine:

ssh orangepi@192.168.1.100

Firewall

sudo apt install ufw -y
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Allow SSH first. Always add the SSH rule before enabling the firewall, or you will lock yourself out of remote access.

GPIO

The Orange Pi RV2 has a 40-pin GPIO header compatible with the Raspberry Pi pinout. Install the GPIO library:

sudo pip3 install OPi.GPIO

Blink an LED

blink_led.py
import OPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)

try:
    while True:
        GPIO.output(11, GPIO.HIGH)
        time.sleep(1)
        GPIO.output(11, GPIO.LOW)
        time.sleep(1)
except KeyboardInterrupt:
    GPIO.cleanup()

Read a button

button_read.py
import OPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)

try:
    while True:
        if GPIO.input(13) == GPIO.LOW:
            GPIO.output(11, GPIO.HIGH)
        else:
            GPIO.output(11, GPIO.LOW)
        time.sleep(0.1)
except KeyboardInterrupt:
    GPIO.cleanup()

Python

Environment setup

python3 --version
python3 -m pip install --upgrade pip
sudo apt install python3-dev python3-venv -y

Virtual environments

python3 -m venv ~/myproject/venv
source ~/myproject/venv/bin/activate
pip install flask requests numpy
deactivate

Hardware libraries

pip install OPi.GPIO        # GPIO control
pip install smbus2          # I2C
pip install spidev          # SPI
pip install pyserial        # UART

I2C temperature sensor

temp_sensor.py
import smbus2
import time

BMP280_ADDR = 0x76
bus = smbus2.SMBus(1)

def read_temperature():
    data = bus.read_i2c_block_data(BMP280_ADDR, 0xFA, 3)
    raw_temp = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
    return raw_temp / 5120.0

try:
    while True:
        temp = read_temperature()
        print(f"Temperature: {temp:.2f}°C")
        time.sleep(2)
except KeyboardInterrupt:
    bus.close()

Flask web monitor

web_monitor.py
from flask import Flask, jsonify
import subprocess, os

app = Flask(__name__)

def get_cpu_temp():
    try:
        temp = subprocess.check_output(["cat", "/sys/class/thermal/thermal_zone0/temp"])
        return float(temp) / 1000
    except:
        return 0

def get_memory_usage():
    with open('/proc/meminfo') as f:
        lines = f.readlines()
    total = int(lines[0].split()[1])
    available = int(lines[2].split()[1])
    return round(((total - available) / total) * 100, 1)

@app.route('/api/status')
def status():
    return jsonify({'cpu_temp': get_cpu_temp(), 'memory_pct': get_memory_usage()})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
pip install flask
python3 web_monitor.py

Run at startup with systemd

/etc/systemd/system/myapp.service
[Unit]
Description=My Python Application
After=network.target

[Service]
Type=simple
User=orangepi
WorkingDirectory=/home/orangepi/myproject
ExecStart=/home/orangepi/myproject/venv/bin/python app.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable myapp.service
sudo systemctl start myapp.service

Docker

Docker runs containerized services on the Orange Pi RV2 with isolated environments and managed dependencies. Install it using the official script:

Installation

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

Log out and back in after adding yourself to the docker group for it to take effect.

sudo apt install docker-compose-plugin -y
docker compose version

Portainer (container management UI)

docker volume create portainer_data
docker run -d \
  --name portainer \
  --restart=always \
  -p 9000:9000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

Access at http://your-ip:9000

Home Assistant

docker-compose.yml
version: '3.8'

services:
  homeassistant:
    container_name: homeassistant
    image: ghcr.io/home-assistant/home-assistant:stable
    volumes:
      - ./homeassistant:/config
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    privileged: true
    network_mode: host
mkdir -p ~/homeassistant && cd ~/homeassistant
docker compose up -d

MQTT + Node-RED + InfluxDB stack

iot-stack/docker-compose.yml
version: '3.8'

services:
  mosquitto:
    container_name: mosquitto
    image: eclipse-mosquitto:latest
    ports:
      - "1883:1883"
      - "9001:9001"
    volumes:
      - ./mosquitto/config:/mosquitto/config
      - ./mosquitto/data:/mosquitto/data
    restart: unless-stopped

  nodered:
    container_name: nodered
    image: nodered/node-red:latest
    ports:
      - "1880:1880"
    volumes:
      - ./nodered:/data
    environment:
      - TZ=America/Port_of_Spain
    depends_on:
      - mosquitto
    restart: unless-stopped

  influxdb:
    container_name: influxdb
    image: influxdb:2.7
    ports:
      - "8086:8086"
    volumes:
      - ./influxdb:/var/lib/influxdb2
    environment:
      - DOCKER_INFLUXDB_INIT_MODE=setup
      - DOCKER_INFLUXDB_INIT_USERNAME=admin
      - DOCKER_INFLUXDB_INIT_PASSWORD=adminpassword
      - DOCKER_INFLUXDB_INIT_ORG=myorg
      - DOCKER_INFLUXDB_INIT_BUCKET=iot
    restart: unless-stopped

Useful commands

docker ps                     # running containers
docker ps -a                  # all containers
docker logs -f container_name # follow logs
docker stats                  # resource usage
docker system prune -a        # clean up unused data
docker system df              # disk usage

SD card wear. Docker writes heavily. If you are running containers long term, move the Docker data directory to an external SSD or eMMC to avoid wearing out the SD card.

RISC-V image compatibility

Not all Docker images support RISC-V yet. Look for images tagged riscv64 or multi-architecture builds. Portainer, Home Assistant, Node-RED, Mosquitto, InfluxDB, Grafana, Nginx, and PostgreSQL all have confirmed RISC-V support. Check Docker Hub before deploying anything else.

Web Server

Turn the Orange Pi RV2 into a web server running Nginx.

Install Nginx

sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx

Your board is now serving the default Nginx page. Open a browser and navigate to the board's IP address to verify.

Deploy your site

Replace the default page with your own HTML:

sudo nano /var/www/html/index.html

HTTPS with Let's Encrypt

If the board has a public domain name, add a free SSL certificate:

sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com
sudo certbot renew --dry-run

IoT Gateway

The Orange Pi RV2 makes a capable IoT gateway. The Docker section on this page includes a ready-to-deploy stack with Mosquitto (MQTT broker), Node-RED (data processing and flow automation), and InfluxDB (time series storage). Together, they give you a complete pipeline: sensors publish data over MQTT, Node-RED transforms and routes it, and InfluxDB stores it for dashboards and analysis.

Add Grafana on top for visualization, or forward data upstream to AWS IoT, Azure IoT Hub, or Google Cloud IoT Core. The Orange Pi handles the local aggregation, buffering, and preprocessing so your cloud bill stays low and your sensors keep logging even when the internet connection drops.

Downloads

OS images, GPIO libraries, and documentation for the Orange Pi RV2.

External Resources