feat: enhance error handling and documentation links in benchmark tools

This commit is contained in:
ob-yalian
2026-08-19 17:10:31 +08:00
parent 758fe03520
commit 89f7cf6da9
6 changed files with 105 additions and 42 deletions
+24 -3
View File
@@ -12,6 +12,7 @@ usage:
"""
import argparse
import sys
import rclpy
from rclpy.node import Node
import psutil
@@ -21,11 +22,24 @@ import os
from collections import defaultdict
from orbbec_camera_msgs.msg import DeviceStatus
from sensor_msgs.msg import Image
import sys
from tabulate import tabulate
CAMERA_NODE_NAMES = ["component_container", "orbbec_camera_node", "nodelet"]
DOCUMENTATION_URL = (
"https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/"
"6_benchmark/benchmark_tools.html"
)
class DocumentationArgumentParser(argparse.ArgumentParser):
def error(self, message):
self.print_usage(sys.stderr)
self.exit(
2,
f"{self.prog}: error: {message}\n"
f"For usage and troubleshooting, see: {DOCUMENTATION_URL}\n",
)
# ----------------tool functions----------------
def parse_duration(s):
@@ -471,7 +485,10 @@ class CameraMonitorNode(Node):
def main(argv=None):
parser = argparse.ArgumentParser()
parser = DocumentationArgumentParser(
epilog=f"Documentation: {DOCUMENTATION_URL}",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--run_time", type=str, default="10s", help="Total run time for monitoring, e.g., 10s, 5m, 1h.")
parser.add_argument("--csv_file", type=str, default="camera_monitor_log.csv")
parser.add_argument("--ideal_fps", type=float, default=0.0, help="Optional ideal frame rate to use for drop detection (overrides reported avg).")
@@ -494,4 +511,8 @@ def main(argv=None):
node.destroy_node()
if __name__ == "__main__":
main()
try:
main()
except Exception:
print(f"For usage and troubleshooting, see: {DOCUMENTATION_URL}", file=sys.stderr)
raise
@@ -23,6 +23,23 @@ from statistics import mean
from tabulate import tabulate
import importlib
import csv
import sys
DOCUMENTATION_URL = (
"https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/"
"6_benchmark/benchmark_tools.html"
)
class DocumentationArgumentParser(argparse.ArgumentParser):
def error(self, message):
self.print_usage(sys.stderr)
self.exit(
2,
f"{self.prog}: error: {message}\n"
f"For usage and troubleshooting, see: {DOCUMENTATION_URL}\n",
)
class ServiceBenchmark:
@@ -180,7 +197,10 @@ class BenchmarkRunner:
def main():
parser = argparse.ArgumentParser()
parser = DocumentationArgumentParser(
epilog=f"Documentation: {DOCUMENTATION_URL}",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument("--service", help="Service name")
parser.add_argument("--count", type=int, default=10, help="Number of calls")
parser.add_argument("--yaml_file", help="YAML config file for batch testing")
@@ -207,4 +227,8 @@ def main():
if __name__ == "__main__":
main()
try:
main()
except Exception:
print(f"For usage and troubleshooting, see: {DOCUMENTATION_URL}", file=sys.stderr)
raise
+7 -1
View File
@@ -33,6 +33,9 @@
#include "orbbec_camera/utils.h"
namespace {
constexpr char kDocumentationUrl[] =
"https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/6_benchmark/"
"firmware_update_tool.html";
constexpr int kProgressLogBucketPercent = 25;
constexpr int kFirmwareLogDrainDelaySec = 5;
@@ -131,7 +134,9 @@ void printUsage() {
<< " 2) If multiple devices are connected, specify target by serial/usb/ip to avoid wrong "
"updates.\n"
<< " 3) Repeating --serial_number or passing comma-separated values enables sequential "
"batch update.\n";
"batch update.\n\n"
<< "Documentation:\n"
<< " " << kDocumentationUrl << "\n";
}
bool parseArgs(int argc, char **argv, CliArgs &args, std::string &error) {
@@ -862,6 +867,7 @@ int main(int argc, char **argv) {
RCLCPP_ERROR(logger, "Unknown error");
}
RCLCPP_ERROR(logger, "For usage and troubleshooting, see: %s", kDocumentationUrl);
rclcpp::shutdown();
return 1;
}
+28 -33
View File
@@ -14,6 +14,9 @@ using namespace ob;
namespace {
constexpr int kFirmwareLogDrainDelaySec = 5;
constexpr char kDocumentationUrl[] =
"https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/6_benchmark/"
"network_config_tools.html";
void waitForFirmwareLogDrain(const rclcpp::Logger &logger) {
RCLCPP_INFO(logger, "Waiting %d seconds to keep firmware log alive...",
@@ -25,6 +28,12 @@ bool isSdkLogEnabled(const std::string &log_level) {
return orbbec_camera::obLogSeverityFromString(log_level) != OBLogSeverity::OB_LOG_SEVERITY_OFF;
}
int reportFailure(const rclcpp::Logger &logger) {
RCLCPP_ERROR(logger, "For usage and troubleshooting, see: %s", kDocumentationUrl);
rclcpp::shutdown();
return 1;
}
} // namespace
struct CliArgs {
@@ -177,7 +186,9 @@ void printHelp() {
<< " Debug: ros2 run orbbec_camera ip_config_tool -- \\\n"
<< " set_ip --current_ip 192.168.1.10 --enable_dhcp true "
"--enable_persistent_ip false \\\n"
<< " --sdk_log_level debug\n";
<< " --sdk_log_level debug\n\n"
<< "Documentation:\n"
<< " " << kDocumentationUrl << "\n";
}
bool parseArgs(int argc, char **argv, CliArgs &args, std::string &error) {
@@ -461,18 +472,15 @@ int main(int argc, char **argv) {
uint8_t gateway[4] = {0};
if (args.persistent_ip && !parseIpString(args.new_ip, address)) {
RCLCPP_ERROR(logger, "Invalid new_ip format: %s", args.new_ip.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (args.persistent_ip && !parseIpString(args.mask, mask)) {
RCLCPP_ERROR(logger, "Invalid mask format: %s", args.mask.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (args.persistent_ip && !parseIpString(args.gateway, gateway)) {
RCLCPP_ERROR(logger, "Invalid gateway format: %s", args.gateway.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
OBNetIpConfigV2 ip_config_v2{};
@@ -521,8 +529,7 @@ int main(int argc, char **argv) {
"Legacy IP config (1041) supports mutually exclusive DHCP and persistent "
"IP only. Use --enable_dhcp true --enable_persistent_ip false or "
"--enable_dhcp false --enable_persistent_ip true.");
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
ip_config.dhcp = args.dhcp ? 1 : 0;
uint8_t address[4] = {0};
@@ -530,18 +537,15 @@ int main(int argc, char **argv) {
uint8_t gateway[4] = {0};
if (args.persistent_ip && !parseIpString(args.new_ip, address)) {
RCLCPP_ERROR(logger, "Invalid new_ip format: %s", args.new_ip.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (args.persistent_ip && !parseIpString(args.mask, mask)) {
RCLCPP_ERROR(logger, "Invalid mask format: %s", args.mask.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (args.persistent_ip && !parseIpString(args.gateway, gateway)) {
RCLCPP_ERROR(logger, "Invalid gateway format: %s", args.gateway.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (args.persistent_ip) {
std::memcpy(ip_config.address, address, sizeof(address));
@@ -579,18 +583,15 @@ int main(int argc, char **argv) {
if (!args.dhcp) {
if (!parseIpString(args.new_ip, ip_config.address)) {
RCLCPP_ERROR(logger, "Invalid new_ip format: %s", args.new_ip.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (!parseIpString(args.mask, ip_config.mask)) {
RCLCPP_ERROR(logger, "Invalid mask format: %s", args.mask.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
if (!parseIpString(args.gateway, ip_config.gateway)) {
RCLCPP_ERROR(logger, "Invalid gateway format: %s", args.gateway.c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
}
@@ -607,8 +608,7 @@ int main(int argc, char **argv) {
}
} else {
RCLCPP_ERROR(logger, "Force-ip failed (SDK returned false).");
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
}
@@ -621,16 +621,14 @@ int main(int argc, char **argv) {
if (!device->isPropertySupported(OB_PROP_DHCP_ASSIGN_IP_TIMEOUT_INT, OB_PERMISSION_WRITE)) {
RCLCPP_ERROR(logger, "Current device or firmware does not support DHCP assign IP timeout");
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
auto range = device->getIntPropertyRange(OB_PROP_DHCP_ASSIGN_IP_TIMEOUT_INT);
if (args.dhcp_assign_ip_timeout < range.min || args.dhcp_assign_ip_timeout > range.max) {
RCLCPP_ERROR(logger, "Timeout %d is out of range [%d, %d]", args.dhcp_assign_ip_timeout,
range.min, range.max);
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
device->setIntProperty(OB_PROP_DHCP_ASSIGN_IP_TIMEOUT_INT, args.dhcp_assign_ip_timeout);
@@ -645,16 +643,13 @@ int main(int argc, char **argv) {
} catch (ob::Error &e) {
RCLCPP_ERROR(logger, "ip_config_tool: %s", orbbec_camera::formatObErrorWithStatus(e).c_str());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
} catch (const std::exception &e) {
RCLCPP_ERROR(logger, "ip_config_tool: %s", e.what());
rclcpp::shutdown();
return 1;
return reportFailure(logger);
} catch (...) {
RCLCPP_ERROR(logger, "ip_config_tool: unknown error");
rclcpp::shutdown();
return 1;
return reportFailure(logger);
}
rclcpp::shutdown();
+8 -2
View File
@@ -15,6 +15,9 @@ using namespace orbbec_camera;
namespace {
constexpr int kFirmwareLogDrainDelaySec = 5;
constexpr char kDocumentationUrl[] =
"https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/6_benchmark/"
"device_query_tools.html";
struct CliArgs {
bool help = false;
@@ -33,7 +36,9 @@ void printUsage() {
"(default: off).\n"
<< " -h, --help Show this help message.\n"
<< "Examples:\n"
<< " ros2 run orbbec_camera list_camera_profile_mode_node -- --sdk_log_level debug\n";
<< " ros2 run orbbec_camera list_camera_profile_mode_node -- --sdk_log_level debug\n\n"
<< "Documentation:\n"
<< " " << kDocumentationUrl << "\n";
}
bool parseArgs(int argc, char** argv, CliArgs& args, std::string& error) {
@@ -116,7 +121,8 @@ std::shared_ptr<ob::Device> initializeDevice(const std::string& serial_number) {
auto context = std::make_shared<ob::Context>();
auto device_list = context->queryDeviceList();
if (!device_list || device_list->getCount() == 0) {
std::cout << "No device found" << std::endl;
std::cout << "No device found\nFor usage and troubleshooting, see: " << kDocumentationUrl
<< std::endl;
return nullptr;
}
+12 -1
View File
@@ -29,6 +29,9 @@
namespace {
constexpr int kFirmwareLogDrainDelaySec = 5;
constexpr char kDocumentationUrl[] =
"https://orbbec.github.io/OrbbecSDK_ROS2/en/source/camera_devices/6_benchmark/"
"device_query_tools.html";
struct CliArgs {
bool help = false;
@@ -42,7 +45,9 @@ void printUsage() {
<< " --sdk_log_level LEVEL SDK file log level: debug/info/warn/error/fatal/off "
"(default: off).\n\n"
<< "Examples:\n"
<< " ros2 run orbbec_camera list_devices_node -- --sdk_log_level debug\n";
<< " ros2 run orbbec_camera list_devices_node -- --sdk_log_level debug\n\n"
<< "Documentation:\n"
<< " " << kDocumentationUrl << "\n";
}
bool parseArgs(int argc, char **argv, CliArgs &args, std::string &error) {
@@ -339,10 +344,16 @@ int main(int argc, char **argv) {
} catch (ob::Error &e) {
RCLCPP_ERROR_STREAM(rclcpp::get_logger("list_device_node"),
orbbec_camera::formatObErrorWithStatus(e));
RCLCPP_ERROR_STREAM(rclcpp::get_logger("list_device_node"),
"For usage and troubleshooting, see: " << kDocumentationUrl);
} catch (const std::exception &e) {
RCLCPP_ERROR_STREAM(rclcpp::get_logger("list_device_node"), e.what());
RCLCPP_ERROR_STREAM(rclcpp::get_logger("list_device_node"),
"For usage and troubleshooting, see: " << kDocumentationUrl);
} catch (...) {
RCLCPP_ERROR_STREAM(rclcpp::get_logger("list_device_node"), "unknown error");
RCLCPP_ERROR_STREAM(rclcpp::get_logger("list_device_node"),
"For usage and troubleshooting, see: " << kDocumentationUrl);
}
return 0;
}