orbbec

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 17 Imported by: 0

README

orbbec-go

CI Go Reference

Pure Go driver for the Orbbec Gemini 435Le Ethernet depth camera — no OrbbecSDK native libraries, no cgo. CGO_ENABLED=0 builds static binaries for Linux (amd64/arm64), Windows and macOS.

It speaks the camera's network protocols directly (GVCP control channel privilege, the vendor control protocol on TCP 8090, RTSP/RTP depth and color streams, on-device calibration), ported from the MIT-licensed OrbbecSDK v2 and checked against the official SDK on real hardware: intrinsics, extrinsics, baseline, frame metadata and the command sequence match, and depth pixels match the SDK's output with its noise filter off.


奥比中光 Gemini 435Le 网口深度相机的纯 Go 驱动:不依赖 OrbbecSDK 原生库,不用 cgo,一个静态二进制就能跑。

功能

  • 设备发现(GVCP 广播)、控制权(CCP)申请 / 保活 / 释放:别的程序占着相机时给出明确错误,不会像原生 SDK 那样把进程带崩
  • 深度流 Y16(1280×800 @ 5/10 fps),单位换算成 mm;彩色流 MJPEG(RFC 2435),保留原始 JPEG 字节方便直接转发
  • 从相机读标定:各分辨率的深度/彩色内参、深度→彩色外参、双目基线;相机报告的有效分辨率列表
  • 每帧元数据:曝光、增益、激光状态、传感器时间戳、帧号
  • 常驻收帧 + 最近 N 帧缓存(多帧取中值不必等相机出帧)、掉线检测、打开重试
  • obprobe 命令行:发现、只读查看、取帧存盘、长时间运行监控

安装

go get github.com/dropp-dev/orbbec-go
go install github.com/dropp-dev/orbbec-go/cmd/obprobe@latest

用法

import "github.com/dropp-dev/orbbec-go"

cam := orbbec.New(orbbec.Config{IP: "192.168.1.10"})
if err := cam.Open(); err != nil { // 拿控制权、读标定、起深度+彩色流
	log.Fatal(err)
}
defer cam.Close() // 关流并释放控制权,别的程序马上能打开

intr := cam.Intrinsics()                                    // 1280x800 深度内参
frames, err := cam.RecentDepths(5, 2*time.Second, time.Second) // 最近 5 帧,Data 单位 mm,0 = 无效
f, err := cam.GrabDepth(time.Second)                        // 下一帧新的深度
color, _ := cam.GrabColor(time.Second)                      // 最新彩色帧(JPEG 字节)
cp := cam.ColorParams()                                     // 彩色内参 + 深度->彩色外参
if !cam.IsAlive(0) {                                        // 断电、拔网线后变 false
	log.Print(cam.LastError())
}

取帧超时返回 ErrTimeout,Close() 之后返回 ErrClosed;IsAlive 只看深度流,彩色流断了不算离线。 帧回调(Device.StartDepth 的 onFrame)在收帧 goroutine 上执行,不要阻塞,也不要在里面调 Close。

更底层的 orbbec.OpenDevice 可以只读打开(不占控制权)、读写属性(如 PropLaserBool)、单独起深度或彩色流; Device.Close() 会先关掉它起的流。

obprobe

obprobe discover                          # 广播找相机
obprobe info  -ip 192.168.1.10            # 只读:设备信息、有效分辨率、深度精度、标定和内参(不占控制权)
obprobe grab  -ip 192.168.1.10 -out /tmp  # 取 5 秒流,报帧率,存 depth.png(16 位,mm)和 color.jpg
obprobe watch -ip 192.168.1.10            # 长时间运行,每 10 秒报一次帧率,掉线自动重连

-precision keep|default|0~6:深度精度档位。default 和官方 SDK 一样设成相机默认档(435Le 是 1 mm), keep 不动相机当前设置(obprobe 默认),库默认是 default。

支持的设备

设备 固件 状态
Gemini 435Le 1.3.19 已在真机上对照官方 SDK 核实

其他 Gemini 330 系列网口相机(335Le 等)走的是另一套 RTP 推流协议,暂不支持。

部署注意

  • 持有控制权期间,OrbbecViewer 等基于官方 SDK 的程序打不开相机(ACCESS_DENIED);Close() 后立即释放,进程被强杀时相机在心跳超时(约 6 s)后自动释放。
  • 不要同时用 VLC、ffmpeg 等直接拉 rtsp://相机IP:8554/...:相机会把帧轮流分给各客户端,后来的客户端断开时还会让先来的停帧约 5 s。
  • 防火墙放行到相机的 TCP 8090/8554/8888 和 UDP 3956。RTSP 走 TCP 交织,不需要调大 UDP 接收缓冲区。

协议概要

通道 端口 用途
GVCP UDP 3956 发现;CCP 寄存器 0x0A00 控制权;心跳超时 0x0938
控制协议 TCP 8090 8 字节头(魔数 0x4D47)+ 属性 ID;响应魔数 0x4252,补零到 1022 字节
RTSP TCP 8554 / 8888 rtsp://IP:8554/depth/1280_800_10_y16、rtsp://IP:8888/color/1280_800_10_mjpg,RTP 交织在同一 TCP 连接

与官方 SDK 的一致性

在 435Le(固件 1.3.19)上对照 OrbbecSDK v2.10.6 核实过:

  • 内参、外参、基线、设备信息、帧时间戳和元数据与 SDK 完全一致;
  • 打开、起流、关流的命令序列与 SDK 一致;
  • 深度像素与关闭去噪的 SDK 输出一致(静止场景中值图 99% 以上像素相差不超过 1 mm,无像素错位)。SDK 默认开着的去噪只额外去掉极少量孤立小斑点,本驱动不做;
  • 彩色 JPEG 的量化表、Huffman 表与 SDK 逐字节相同。

测试

go test -race ./...                       # 内置模拟相机(GVCP + 控制协议 + RTSP),标定数据来自真机
go test -run='^$' -fuzz=FuzzJPEG -fuzztime=30s .   # 协议解析器的 fuzz(FuzzParseRTP / FuzzJPEG / FuzzVendorFrame / FuzzGVCPAndCalib)

许可证

MIT。协议实现移植自 OrbbecSDK v2(MIT,Copyright (c) 2024-2026 Orbbec Inc),见 NOTICE。 本项目与奥比中光无关,"Orbbec" 是奥比中光的商标。

Documentation

Overview

Package orbbec 是奥比中光 Gemini 435Le 网口深度相机的纯 Go 驱动,不依赖 OrbbecSDK 原生库,不用 cgo。

协议移植自 OrbbecSDK v2(MIT,Copyright (c) Orbbec Inc.):

  • GVCP(UDP 3956):设备发现;CCP 寄存器 0x0A00 控制权的申请、保活和释放。
  • 控制协议(TCP 8090):属性、结构体、V1.1 结构体列表。
  • RTSP(TCP 8554 深度、8888 彩色),RTP 交织在同一连接上。
  • 标定:深度/彩色内参、深度到彩色外参、基线、有效分辨率。

用法:

cam := orbbec.New(orbbec.Config{IP: "192.168.1.10"})
if err := cam.Open(); err != nil {
	log.Fatal(err)
}
defer cam.Close()
frames, err := cam.RecentDepths(5, 2*time.Second, time.Second)

Index

Constants

View Source
const (
	GevStatusSuccess      uint16 = 0x0000
	GevStatusAccessDenied uint16 = 0x8006
	GevStatusError        uint16 = 0x8FFF
)

GVCP 状态码。

View Source
const (
	SensorIR         = 1
	SensorColor      = 2
	SensorDepth      = 3
	SensorIRLeft     = 6
	SensorIRRight    = 7
	SensorConfidence = 9

	FormatYUYV  = 0
	FormatMJPG  = 5
	FormatY16   = 8
	FormatY8    = 9
	FormatI420  = 15
	FormatRVL   = 27
	FormatY12C4 = 34
)

传感器类型和像素格式(OBSensorType / OBFormat)。

View Source
const (
	PropLaserBool                     uint32 = 3
	PropStopDepthStreamBool           uint32 = 38
	PropDepthAlignHardwareBool        uint32 = 42 // 硬件 D2C,开着时深度被对齐到彩色视角
	PropDepthPrecisionLevelInt        uint32 = 75
	PropStopColorStreamBool           uint32 = 77
	PropDisparityToDepthBool          uint32 = 85
	PropDeviceCommunicationTypeInt    uint32 = 97 // 1 = 网口
	PropDevicePIDInt                  uint32 = 111
	PropCompatVersionInt              uint32 = 237 // 1 = 彩色 JPEG 内嵌元数据
	PropColorAutoExposureBool         uint32 = 2000
	PropIRAutoExposureBool            uint32 = 2025
	StructVersion                     uint32 = 1000
	RawDataD2CAlignSupportProfileList uint32 = 4024
	RawDataDepthCalibParam            uint32 = 4026
	RawDataAlignCalibParam            uint32 = 4027
	RawDataEffectiveStreamProfileList uint32 = 4035
)

属性 ID(OrbbecSDK 的 Property.h / InternalProperty.hpp)。

Variables

View Source
var (
	// ErrTimeout 表示在给定时间内没有等到帧。
	ErrTimeout = errors.New("timed out waiting for a frame")
	// ErrAlreadyOpen 表示 Camera 已经打开。
	ErrAlreadyOpen = errors.New("camera is already open")
)
View Source
var ErrAccessDenied = errors.New("camera is controlled by another application (GVCP access denied)")

ErrAccessDenied 表示控制权在别的程序手里。持有者异常退出时,相机在心跳超时后自动释放。

View Source
var ErrClosed = errors.New("device is closed")

ErrClosed 表示设备或相机已经关闭。

Functions

This section is empty.

Types

type Calibration

type Calibration struct {
	Depth []DepthCalibParam
	// contains filtered or unexported fields
}

Calibration 是从相机读出的标定数据。

func (*Calibration) BaselineMM

func (c *Calibration) BaselineMM() float64

BaselineMM 返回双目基线(mm),未知时为 0。

func (*Calibration) ColorIntrinsics

func (c *Calibration) ColorIntrinsics(w, h int) (Intrinsics, error)

ColorIntrinsics 返回 w×h 彩色流的内参。

func (*Calibration) DepthIntrinsics

func (c *Calibration) DepthIntrinsics(w, h int) (Intrinsics, error)

DepthIntrinsics 返回 w×h 深度流的内参。

func (*Calibration) DepthToColor

func (c *Calibration) DepthToColor() (Extrinsic, bool)

DepthToColor 返回深度到彩色的外参。

type Camera

type Camera struct {
	// contains filtered or unexported fields
}

Camera 持续接收深度和彩色并缓存最近几帧。深度流停了 IsAlive 返回 false,Close 再 Open 即可重连。 返回的帧是共享的,只读;要修改先 Clone。必须用 New 创建;Open/Close 可以和取帧方法并发调用。

func New

func New(cfg Config) *Camera

New 创建相机对象,不连接。

func (*Camera) BaselineMM

func (c *Camera) BaselineMM() float64

BaselineMM 返回双目基线(mm),未知时为 0。

func (*Camera) Close

func (c *Camera) Close() error

Close 关流并释放控制权,可重复调用;会中断正在进行的 Open。

func (*Camera) ColorParams

func (c *Camera) ColorParams() *ColorParams

ColorParams 返回彩色内参和深度到彩色外参(副本),没有彩色流时为 nil。

func (*Camera) DeviceInfo

func (c *Camera) DeviceInfo() DeviceInfo

DeviceInfo 返回设备信息。

func (*Camera) GrabColor

func (c *Camera) GrabColor(timeout time.Duration) (*ColorFrame, error)

GrabColor 返回最新的彩色帧,没有时最多等 timeout,仍没有则返回 ErrTimeout。

func (*Camera) GrabDepth

func (c *Camera) GrabDepth(timeout time.Duration) (*DepthFrame, error)

GrabDepth 返回下一帧新的深度图;超时返回 ErrTimeout,关闭返回 ErrClosed。

func (*Camera) HasColor

func (c *Camera) HasColor() bool

HasColor 表示 AliveTimeout 内收到过彩色帧。

func (*Camera) Intrinsics

func (c *Camera) Intrinsics() Intrinsics

Intrinsics 返回深度流内参。

func (*Camera) IsAlive

func (c *Camera) IsAlive(maxAge time.Duration) bool

IsAlive 表示 maxAge(0 用 AliveTimeout)内收到过深度帧。

func (*Camera) LastError

func (c *Camera) LastError() string

LastError 返回离线原因,在线时为空。

func (*Camera) LatestColor

func (c *Camera) LatestColor(newerThan uint64, timeout time.Duration) (*ColorFrame, uint64)

LatestColor 等到序号大于 newerThan 的彩色帧后返回,超时则返回当前最新帧;没有彩色帧时返回 nil。

func (*Camera) Open

func (c *Camera) Open() error

Open 连接相机并开始取流,失败时按 RetryWait 重试。已打开时返回 ErrAlreadyOpen。

func (*Camera) OpenContext

func (c *Camera) OpenContext(ctx context.Context) error

OpenContext 同 Open,可取消;Close 也会中断正在进行的打开。

func (*Camera) RecentDepths

func (c *Camera) RecentDepths(n int, timeout, maxAge time.Duration) ([]*DepthFrame, error)

RecentDepths 返回缓存里最近 n 帧(按时间先后)。最新一帧早于 maxAge(0 用 AliveTimeout)时等新帧, 避免离线后用旧帧。

type ColorFrame

type ColorFrame struct {
	Width, Height int
	JPEG          []byte
	Seq           uint64
	Time          time.Time
	Metadata      []byte // JPEG COM 段里的帧元数据
}

ColorFrame 是一帧彩色图,保留相机发来的 JPEG 字节。

func (*ColorFrame) Clone

func (f *ColorFrame) Clone() *ColorFrame

Clone 深拷贝一帧(JPEG 和 Metadata 都复制)。

type ColorParams

type ColorParams struct {
	Intrinsics Intrinsics `json:"intr"`
	DepthToRGB Extrinsic  `json:"extrinsic"`
}

ColorParams 是彩色相机内参和深度到彩色的外参。

type Config

type Config struct {
	IP     string
	Logger *slog.Logger
	// 端口,0 用默认值。
	GVCPPort, ControlPort, DepthRTSPPort, ColorRTSPPort int

	Depth StreamConfig // 默认 1280x800@10
	// Color 为 nil 时用 1280x800@10;NoColor 为 true 时不开彩色流(优先于 Color)。
	Color   *StreamConfig
	NoColor bool

	DepthPrecision *DepthPrecision // 见 DeviceOptions.DepthPrecision

	RingSize         int           // 缓存的深度帧数,默认 8
	AliveTimeout     time.Duration // 多久没有新深度帧算离线,默认 3 s
	OpenRetries      int           // 默认 5
	RetryWait        time.Duration // 默认 3 s
	FrameIdleTimeout time.Duration // 见 DeviceOptions.FrameIdleTimeout
}

Config 是 Camera 的参数,零值字段用默认值。

type DepthCalibParam

type DepthCalibParam struct {
	DepthMode   uint32
	Baseline    float32
	Z0          float32
	FocalPix    float32
	Unit        float32
	DispOffset  float32
	InvalidDisp int32
}

DepthCalibParam 是深度标定参数(OBDepthCalibrationParam,28 字节)。

type DepthFrame

type DepthFrame struct {
	Width, Height     int
	Data              []uint16
	Seq               uint64 // 本地序号,从 1 开始
	DeviceSeq         uint64 // 相机帧号
	DeviceTimestampUs uint64
	Time              time.Time // 主机收到的时间
	Metadata          []byte    // 原始帧元数据,用 ParseFrameMetadata 解析
}

DepthFrame 是一帧深度图,Data 按行存储,单位 mm,0 表示无效。

func (*DepthFrame) At

func (f *DepthFrame) At(u, v int) uint16

At 返回 (u, v) 处的深度。

func (*DepthFrame) Clone

func (f *DepthFrame) Clone() *DepthFrame

Clone 深拷贝一帧(Data 和 Metadata 都复制)。

type DepthPrecision

type DepthPrecision int32

DepthPrecision 是深度精度档位,决定一个深度值代表多少 mm。

const (
	Precision1mm   DepthPrecision = 0
	Precision0mm8  DepthPrecision = 1
	Precision0mm4  DepthPrecision = 2
	Precision0mm1  DepthPrecision = 3
	Precision0mm2  DepthPrecision = 4
	Precision0mm5  DepthPrecision = 5
	Precision0mm05 DepthPrecision = 6

	// PrecisionKeep 表示不改相机当前档位。
	PrecisionKeep DepthPrecision = -1
)

func (DepthPrecision) Unit

func (p DepthPrecision) Unit() (float32, error)

Unit 返回该档位的深度单位(mm)。

type Device

type Device struct {
	// contains filtered or unexported fields
}

Device 是一台已连接的相机。方法可以并发调用;Close 后其它方法返回 ErrClosed。

func OpenDevice

func OpenDevice(ctx context.Context, opts DeviceOptions) (*Device, error)

OpenDevice 连接相机并初始化,顺序和官方 SDK 一致:申请控制权 → 设通信方式和兼容版本 → 读版本、标定和有效分辨率 → 开相机端视差转深度、设深度精度。ctx 只管打开过程。

func (*Device) Calibration

func (d *Device) Calibration() *Calibration

Calibration 返回从相机读出的标定(只读)。

func (*Device) Close

func (d *Device) Close() error

Close 关掉这台设备起的所有流、释放控制权并断开,可重复调用。

func (*Device) ControlLost

func (d *Device) ControlLost() bool

ControlLost 表示控制权被别的程序拿走了。

func (*Device) DepthUnitMM

func (d *Device) DepthUnitMM() float32

DepthUnitMM 返回当前深度单位(mm)。

func (*Device) GetProperty

func (d *Device) GetProperty(id uint32) (int32, error)

GetProperty 读一个整型/布尔属性的当前值。

func (*Device) GetPropertyRange

func (d *Device) GetPropertyRange(id uint32) (PropertyRange, error)

GetPropertyRange 读一个属性的当前值和范围。

func (*Device) Info

func (d *Device) Info() DeviceInfo

func (*Device) Profiles

func (d *Device) Profiles() []EffectiveProfile

Profiles 返回相机报告的有效流配置(副本)。

func (*Device) SetProperty

func (d *Device) SetProperty(id uint32, v int32) error

SetProperty 写一个整型/布尔属性。改深度精度会更新 DepthUnitMM,但已在收的深度流仍按旧单位换算, 要先关流再改。

func (*Device) StartColor

func (d *Device) StartColor(ctx context.Context, cfg StreamConfig, onFrame func(*ColorFrame)) (*Stream, error)

StartColor 开彩色流(MJPEG),onFrame 收到完整 JPEG。约束同 StartDepth。

func (*Device) StartDepth

func (d *Device) StartDepth(ctx context.Context, cfg StreamConfig, onFrame func(*DepthFrame)) (*Stream, error)

StartDepth 开深度流(Y16),onFrame 在读循环里调用:不能阻塞,也不能调用 Close。ctx 只管起流过程。

func (*Device) Version

func (d *Device) Version() VersionInfo

type DeviceError

type DeviceError struct {
	PropertyID uint32
	Opcode     uint16
	Code       uint16
	Msg        string
}

DeviceError 是相机对命令返回的错误码。

func (*DeviceError) Error

func (e *DeviceError) Error() string

type DeviceInfo

type DeviceInfo struct {
	Name       string `json:"name"`
	Serial     string `json:"serial"`
	Firmware   string `json:"firmware"`
	Hardware   string `json:"hardware,omitempty"`
	Connection string `json:"connection"`
	PID        uint16 `json:"pid,omitempty"`
	IP         string `json:"ip,omitempty"`
	MAC        string `json:"mac,omitempty"`
}

DeviceInfo 是设备信息。

type DeviceOptions

type DeviceOptions struct {
	IP     string
	Logger *slog.Logger
	// ReadOnly 不申请控制权、不写属性,可以和别的程序同时连着,但不能取流。
	ReadOnly bool
	// DepthPrecision 为 nil 时设成相机默认档(和官方 SDK 一致),PrecisionKeep 保持当前档位。
	DepthPrecision *DepthPrecision

	// 端口,0 用默认值。
	GVCPPort, ControlPort, DepthRTSPPort, ColorRTSPPort int

	// FrameIdleTimeout 内收不到流数据就认为流断了,默认 10 s。
	// 另一个客户端断开同一路流时相机会停发约 5 s,所以别设得太短。
	FrameIdleTimeout time.Duration
}

DeviceOptions 是打开设备的参数。

type DiscoveredDevice

type DiscoveredDevice struct {
	IP           string
	Mask         string
	Gateway      string
	MAC          string
	Manufacturer string
	Model        string
	PID          uint16
	Firmware     string
	Serial       string
	UserName     string
	LocalIP      string // 收到应答的本机地址
}

DiscoveredDevice 是 GVCP 发现应答里的设备信息。

func Discover

func Discover(ctx context.Context, wait time.Duration) ([]DiscoveredDevice, error)

Discover 在每块 IPv4 网卡的子网上广播发现命令,返回 wait 内收到应答的设备。

type EffectiveProfile

type EffectiveProfile struct {
	Sensor, Format        uint32
	Width, Height, MaxFPS int
}

EffectiveProfile 是相机报告的一个可用流配置。

func (EffectiveProfile) String

func (p EffectiveProfile) String() string

type Extrinsic

type Extrinsic struct {
	R [9]float64 `json:"R"`
	T [3]float64 `json:"t"`
}

Extrinsic 是刚体变换 p_dst = R·p_src + T,R 按行存储,T 单位 mm。

type FrameMetadata

type FrameMetadata struct {
	FrameCounter      uint32
	SensorTimestampUs int64 // 曝光起始时间
	Exposure          uint32
	DigitalGain       uint16
	AnalogGain        uint16
	AutoExposure      bool

	// 仅深度帧
	Width, Height   uint16
	GainLevel       uint16
	LaserPower      uint16
	LaserPowerLevel uint8
	LaserStatus     uint8
	ActualFPS       uint8
}

FrameMetadata 是每帧 108 字节元数据里的常用字段。

func ParseFrameMetadata

func ParseFrameMetadata(b []byte, depth bool) (FrameMetadata, error)

ParseFrameMetadata 解析帧元数据,depth 为 true 时按深度帧布局解析。

type Intrinsics

type Intrinsics struct {
	Width  int     `json:"width"`
	Height int     `json:"height"`
	Fx     float64 `json:"fx"`
	Fy     float64 `json:"fy"`
	Cx     float64 `json:"cx"`
	Cy     float64 `json:"cy"`
}

Intrinsics 是针孔相机内参。

type PropertyRange

type PropertyRange struct {
	Cur, Max, Min, Def, Step int32
}

PropertyRange 是属性的当前值和范围,布尔和浮点属性也按 int32 传输。

type Stream

type Stream struct {
	// contains filtered or unexported fields
}

Stream 是一路正在接收的流。

func (*Stream) Close

func (s *Stream) Close()

Close 结束会话并等读循环退出,可重复调用。不能在 onFrame 回调里调用(回调在读循环上执行,会死锁)。

func (*Stream) Done

func (s *Stream) Done() <-chan struct{}

Done 在读循环退出后关闭;此时连接已关,Err 给出原因(正常 Close 时为 nil)。

func (*Stream) Err

func (s *Stream) Err() error

Err 返回流异常结束的原因。

func (*Stream) Stats

func (s *Stream) Stats() (frames, dropped int64)

Stats 返回收到的帧数和丢弃的帧数。

type StreamConfig

type StreamConfig struct {
	Width, Height, FPS int
}

StreamConfig 是一路流的分辨率和帧率。

type VersionInfo

type VersionInfo struct {
	Firmware, Hardware, MinSDK, DepthChip, SystemChip, Serial string
	DeviceType                                                int32
	DeviceName, SubSystem                                     string
}

VersionInfo 是设备版本信息(OBVersionInfo)。

Directories

Path Synopsis
cmd
obprobe command
Command obprobe inspects a Gemini 435Le camera.
Command obprobe inspects a Gemini 435Le camera.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL