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

204 lines
5.5 KiB
C++

#ifndef __UT_EXCEPTION_HPP__
#define __UT_EXCEPTION_HPP__
#include <unitree/common/error.hpp>
#define UT_MAX_TRACE_ADDR_NUMBER 64
namespace unitree
{
namespace common
{
class Exception : public std::exception
{
public:
Exception() throw()
: Exception(UT_ERR_UNKNOWN, UT_DESC_ERR(UT_ERR_UNKNOWN))
{}
Exception(int32_t code, const std::string& message) throw()
: mCode(code), mMessage(message), mLine(0)
{}
virtual ~Exception()
{}
int32_t GetCode() const
{
return mCode;
}
const std::string& GetMessage() const
{
return mMessage;
}
virtual const char* what() const noexcept
{
return mMessage.c_str();
}
virtual std::string GetClassName() const
{
return "Exception";
}
void Init(const char* file, const char* func, int32_t line)
{
mFile = file;
mFunc = func;
mLine = line;
}
std::string ToString() const
{
std::ostringstream os;
AddDetail(os);
return os.str();
}
std::string StackTrace() const
{
std::ostringstream os;
AddDetail(os);
AddBackTrace(os);
return os.str();
}
protected:
void AddDetail(std::ostringstream& os) const
{
os << "Catch " << GetClassName() << " code:" << mCode
<< ", message:" << mMessage << std::endl;
if (!mFile.empty() && !mFunc.empty() && mLine > 0)
{
os << " at __FILE__:" << mFile << ", __LINE__:"
<< mLine << ", __FUNCTION__:" << mFunc << std::endl;
}
}
void AddBackTrace(std::ostringstream& os) const
{
os << "Stack:" << std::endl;
void* addr[UT_MAX_TRACE_ADDR_NUMBER];
int32_t number = backtrace(addr, UT_MAX_TRACE_ADDR_NUMBER);
char **info = backtrace_symbols(addr, number);
if(info == NULL)
{
return;
}
for(int32_t i=0; i<number; i++)
{
os << info[i] << std::endl;
}
free(info);
}
protected:
int32_t mCode;
std::string mMessage;
std::string mFile;
std::string mFunc;
int32_t mLine;
std::string mWhat;
};
#define UT_THROW_0(ExceptionType) \
do \
{ \
ExceptionType __temp_except_r38e2d; \
__temp_except_r38e2d.Init(__FILE__,__PRETTY_FUNCTION__,__LINE__); \
throw(__temp_except_r38e2d); \
} while(0);
#define UT_THROW(ExceptionType, args...) \
do \
{ \
ExceptionType __temp_except_r38e2d(args); \
__temp_except_r38e2d.Init(__FILE__,__PRETTY_FUNCTION__,__LINE__); \
throw(__temp_except_r38e2d); \
} while(0);
#define UT_THROW_IF(condition, ExceptionType, args...) \
if (condition) \
{ \
UT_THROW(ExceptionType, args); \
}
#define UT_EXCEPTION_TRY \
try \
{
#define __UT_EXCEPTION_CATCH(except, l, t) \
catch (const except& e) \
{ \
if (l) \
{ \
LOG_ERROR(l, e.what()); \
} \
if (t) \
{ \
throw e; \
} \
}
#define UT_EXCEPTION_CATCH(l, t) \
} \
__UT_EXCEPTION_CATCH(unitree::common::Exception, l, t) \
__UT_EXCEPTION_CATCH(std::exception, l, t)
#define UT_DECL_EXCEPTION(ExceptionType, code, desc) \
class ExceptionType : public unitree::common::Exception \
{ \
public: \
ExceptionType() throw() \
: Exception(code, desc) \
{} \
\
ExceptionType(const std::string& message) throw() \
: Exception(code, message) \
{} \
\
std::string GetClassName() const \
{ \
return #ExceptionType; \
} \
};
UT_DECL_EXCEPTION(CommonException, UT_ERR_COMMON, UT_DESC_ERR(UT_ERR_COMMON))
UT_DECL_EXCEPTION(SystemException, UT_ERR_SYSTEM, UT_DESC_ERR(UT_ERR_SYSTEM))
UT_DECL_EXCEPTION(NetworkException, UT_ERR_NETWORK, UT_DESC_ERR(UT_ERR_NETWORK))
UT_DECL_EXCEPTION(FileException, UT_ERR_FILE, UT_DESC_ERR(UT_ERR_FILE))
UT_DECL_EXCEPTION(SocketException, UT_ERR_SOCKET, UT_DESC_ERR(UT_ERR_SOCKET))
UT_DECL_EXCEPTION(IOException, UT_ERR_IO, UT_DESC_ERR(UT_ERR_IO))
UT_DECL_EXCEPTION(LockException, UT_ERR_LOCK, UT_DESC_ERR(UT_ERR_LOCK))
UT_DECL_EXCEPTION(TimeoutException, UT_ERR_TIMEOUT, UT_DESC_ERR(UT_ERR_TIMEOUT))
UT_DECL_EXCEPTION(BadCastException, UT_ERR_BADCAST, UT_DESC_ERR(UT_ERR_BADCAST))
UT_DECL_EXCEPTION(JsonException, UT_ERR_JSON, UT_DESC_ERR(UT_ERR_JSON))
UT_DECL_EXCEPTION(FutureException, UT_ERR_FUTURE, UT_DESC_ERR(UT_ERR_FUTURE))
UT_DECL_EXCEPTION(FutureFaultException, UT_ERR_FUTURE_FAULT, UT_DESC_ERR(UT_ERR_FUTURE_FAULT))
}
}
#endif//__UT_EXCEPTION_HPP__