kassam 2a78f1b609 Record/replay studio, manual recorder kit, and new-robot install tooling
Dashboard (web/hand_web.py)
- Record/replay panel driving g1_record_replay.py as a pty child: take library
  (replay/download/duplicate/rename/delete/upload/delete-all), pause & resume,
  and in-take key buttons that grey out in the --fingers modes the recorder
  ignores (measured: in touch mode the keys change nothing at all).
- /api/restart is container-aware: it kills inspire_g1 and lets the supervisor
  relaunch it. It used to run manage.sh, which started a SECOND inspire_g1
  beside the supervised one - two writers on one RS-485 bus - and never
  returned.
- Shape/combo libraries take a .bak on every write, with an undo button. Both
  files are rewritten in full, so deleting the last entry was unrecoverable.

recorder/
- The recorder lives in this project now: one source of truth for the CLI and
  the dashboard, with pause/resume added to replay.
- record.sh picks a runtime by itself (a python with the SDK, the vendored SDK,
  or the inspire-hand container). bundle.sh packs a ~340KB portable kit.

tools/
- preflight.sh: read-only readiness report for a new robot (hardware, docker,
  build prerequisites, per-robot settings) ending in an install-path verdict.
- fetch_deps.sh: stage build dependencies, verifying the libs are aarch64.
- export_ui.py: regenerate an embedding app's vendored copy of the UI.

docker/
- build_image.sh resolves its dependencies from several layouts: deps/ inside
  the project, /usr/local, a source install prefix, or a ROS2 colcon workspace
  (where the idl headers live when /usr/local has none).
- web/ is copied in the last layer, so dashboard edits skip the C++ rebuild.
- restart=always, and start.sh always builds so an edit cannot silently run a
  stale image.

deps/unitree_sdk2 is vendored so a robot that has never seen the SDK can build.
Docs: README quickstart + embedding notes, SETUP_G1 corrected (that udev rule
stopped creating /dev/inspire_* symlinks a while ago), ROBOT_README describing
a live install.
2026-08-28 20:27:28 +04:00

60 lines
1.4 KiB
C++

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <filesystem>
#include <algorithm>
#include <optional>
#include <chrono>
#include <iomanip>
#include "robot_controller.hpp"
#include "user_controller.hpp"
#include "robot_interface.hpp"
using namespace unitree::common;
using namespace unitree::robot;
namespace fs = std::filesystem;
int main(int argc, char const *argv[])
{
std::string param_folder;
// parse command line params
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
if (arg == "--param" && i + 1 < argc)
{
param_folder = argv[i + 1];
}
}
fs::path param = fs::current_path() / param_folder;
// log
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%Y_%m_%d_%H_%M_%S");
fs::path log_folder = fs::current_path() / "logs" / ss.str();
fs::create_directories(log_folder);
std::ofstream cfg_file(log_folder / "cfg.txt");
cfg_file << "param_folder: " << param << std::endl;
cfg_file.close();
fs::path log_file_name = log_folder / "log.txt";
RobotController<ExampleUserController> robot_controller(log_file_name);
robot_controller.LoadParam(param);
robot_controller.InitDdsModel();
robot_controller.StartControl();
return 0;
}