refactor(log): 日志文案改 ASCII 英文,修 ROS_INFO 中文乱码

ROS_INFO/WARN/ERROR 走的不是 printf,而是 rosconsole -> log4cxx,后者按进程当前的
C 语言环境对消息做一次窄/宽字符转码。节点从未调用 setlocale,LC_CTYPE 停在默认的
"C"(ASCII),于是非 ASCII 的每个字节被替换成一个 '?'——一个汉字 3 字节正好 3 个
'?'。而 [config] 摘要那条 std::cout 路径直接写字节、不转码,所以之前只有 ROS_* 的
日志乱码。备选方案是 setlocale(LC_CTYPE, "")(3 行即可修),这里采用"运行时输出一律
英文":英文日志不依赖语言环境,systemd/robot_upstart 拉起时也不会因缺 LANG 复发。

改动与校验:
- invicta_hardware / invicta_remote / invicta_deploy / invicta_msgs 共 20 个文件、
  202 处字符串字面量改为 ASCII 英文。中文代码注释、标识符、话题名、JSON/TOML 键名、
  日志前缀一律未动(把字面量内容挖空后与改前做骨架比对,20 个文件零差异)。
- printf 格式说明符(%s/%d/%zu/%.1f/%02X ...)的数量、类型、顺序逐文件与改前一致。
- 顺带 ASCII 化非中文字符:° -> deg、± -> +/-、× -> x、→ -> ->、框线 -> "+==+",
  并修正了启动横幅框线宽度差 2 列的问题。
- motion_defs.h 的 GaitName / MotionParamName 显示名改英文(只用于日志与回包文案);
  协议字段仍传整数(bs["MotionState"] = int(...)),不影响上位机协议。

注意:invicta_remote 回给手柄的 Unsupported / "Not allowed operation" 文案也变为英文,
会出现在上位机错误列表里。

已在 SBC(aarch64, Noetic)编译确认。
This commit is contained in:
2026-10-23 15:39:55 +08:00
parent 46bbb06978
commit 944774eab3
20 changed files with 177 additions and 177 deletions
@@ -34,7 +34,7 @@ public:
InvictaInterface(const std::string& robot_name, int dof_num)
: RobotInterface(robot_name, dof_num), cfg_(invicta::Config()) {
if (dof_num_ != cfg_.dof) {
ROS_WARN("[InvictaInterface] 传入 dof=%d 与配置的 %d 不一致,按配置执行", dof_num_, cfg_.dof);
ROS_WARN("[InvictaInterface] passed dof=%d does not match configured %d, using config value", dof_num_, cfg_.dof);
}
joint_pos_ = VecXf::Zero(dof_num_);
joint_vel_ = VecXf::Zero(dof_num_);
@@ -58,7 +58,7 @@ public:
SendStartupSequence();
std::cout << "[InvictaInterface] topics: " << cfg_.topic_joint_states << " / " << cfg_.topic_imu << " -> "
<< cfg_.topic_joint_commands << std::endl;
std::cout << "[InvictaInterface] 模型帧透传:dir/offset 由 invicta_hardware 施加" << std::endl;
std::cout << "[InvictaInterface] model frame passthrough: dir/offset applied by invicta_hardware" << std::endl;
}
virtual void Stop() {}
@@ -124,21 +124,21 @@ protected:
ros::Duration(0.01).sleep();
}
if (cmd_pub_.getNumSubscribers() == 0) {
std::cout << "[InvictaInterface] 警告:joint_commands 还没有订阅者,启动时序可能丢失" << std::endl;
std::cout << "[InvictaInterface] warning: joint_commands has no subscribers yet, startup sequence may be lost" << std::endl;
}
const uint16_t seq[] = {invicta_msgs::kDisable, invicta_msgs::kErrorReset, invicta_msgs::kEnable};
for (uint16_t word : seq) {
PublishRawCommand(word);
ros::Duration(0.01).sleep();
}
std::cout << "[InvictaInterface] 启动控制序列完成 (disable -> error_reset -> enable)" << std::endl;
std::cout << "[InvictaInterface] startup control sequence complete (disable -> error_reset -> enable)" << std::endl;
}
// ------------------------------------------------------------------ 回调
void JointStateHandler(const sensor_msgs::JointState::ConstPtr& msg) {
const size_t n = size_t(dof_num_);
if (msg->position.size() != n || msg->velocity.size() != n || msg->effort.size() != n) {
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s 长度应为 %d,收到 pos=%zu vel=%zu eff=%zu,丢帧",
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s length should be %d, got pos=%zu vel=%zu eff=%zu, dropping frame",
cfg_.topic_joint_states.c_str(), dof_num_, msg->position.size(), msg->velocity.size(),
msg->effort.size());
return;
@@ -159,11 +159,11 @@ protected:
}
if (!by_name && !warned_name_mismatch_) {
warned_name_mismatch_ = true;
ROS_WARN("[InvictaInterface] %s 未按约定给出 %d 个 name,按数组下标解析",
ROS_WARN("[InvictaInterface] %s did not provide the agreed %d names, resolving by array index",
cfg_.topic_joint_states.c_str(), dof_num_);
}
if (unknown > 0) {
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s 有 %d 个关节名不认识,已忽略",
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s has %d unknown joint names, ignored",
cfg_.topic_joint_states.c_str(), unknown);
}
@@ -182,7 +182,7 @@ protected:
if (msg->orientation_covariance[0] == -1.0) {
if (!warned_imu_no_orientation_) {
warned_imu_no_orientation_ = true;
ROS_WARN("[InvictaInterface] %s 没有提供 orientation(covariance=-1),姿态观测无效",
ROS_WARN("[InvictaInterface] %s did not provide orientation (covariance=-1), attitude observation invalid",
cfg_.topic_imu.c_str());
}
return;
@@ -190,7 +190,7 @@ protected:
Eigen::Quaternionf q(float(msg->orientation.w), float(msg->orientation.x), float(msg->orientation.y),
float(msg->orientation.z));
if (q.norm() < 1e-6f) {
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s 四元数模长近零,忽略该帧", cfg_.topic_imu.c_str());
ROS_WARN_THROTTLE(5.0, "[InvictaInterface] %s quaternion norm near zero, ignoring this frame", cfg_.topic_imu.c_str());
return;
}
q.normalize();
@@ -47,12 +47,12 @@ public:
void Start() override {
if (msfb_) msfb_->UpdateCurrentGait(uint32_t(default_gait_));
std::cout << "\n╔════════════════════════════════════════════════╗\n"
<< "║ INVICTA MOTION COMMAND LINK ║\n"
<< "╚════════════════════════════════════════════════╝\n"
<< " 指令来源: " << topic_ << "(由 invicta_remote 发布)\n"
<< " 默认步态: " << GaitName(uint32_t(default_gait_)) << "\n"
<< " 已支持步态: " << SupportedGaitList() << "\n\n";
std::cout << "\n+==================================================+\n"
<< "| INVICTA MOTION COMMAND LINK |\n"
<< "+==================================================+\n"
<< " Command source: " << topic_ << " (published by invicta_remote)\n"
<< " Default gait: " << GaitName(uint32_t(default_gait_)) << "\n"
<< " Supported gaits: " << SupportedGaitList() << "\n\n";
}
void Stop() override {}
@@ -61,7 +61,7 @@ public:
private:
std::string SupportedGaitList() const {
if (!loaded_gaits_ || loaded_gaits_->empty()) return "(无)";
if (!loaded_gaits_ || loaded_gaits_->empty()) return "(none)";
std::string s;
for (int gait : *loaded_gaits_) {
char buf[16];
@@ -83,39 +83,39 @@ private:
switch (int(target)) {
case kMotionStanding:
name = "站立";
name = "stand up";
next = uint8_t(RobotMotionState::StandingUp);
accepted = (cur == RobotMotionState::WaitingForStand || cur == RobotMotionState::LieDown);
break;
case kMotionJointDamping:
name = "关节阻尼";
name = "joint damping";
next = uint8_t(RobotMotionState::JointDamping);
accepted = true;
break;
case kMotionBootDamping:
name = "开机阻尼(按关节阻尼处理)";
name = "boot damping (handled as joint damping)";
next = uint8_t(RobotMotionState::JointDamping);
accepted = true;
break;
case kMotionLieDown:
name = "趴下";
name = "lie down";
next = uint8_t(RobotMotionState::LieDown);
accepted = (cur == RobotMotionState::StandingUp || cur == RobotMotionState::RLControlMode);
break;
case kMotionRlControl:
name = "RL控制";
name = "RL control";
next = uint8_t(RobotMotionState::RLControlMode);
accepted = (cur == RobotMotionState::StandingUp);
break;
case kMotionIdle:
// 状态机没有「直接回空闲」的路径(RL / 站立只能经阻尼或趴下退出),不作为请求
if (last_request_ != kMotionIdle) {
std::cout << "[MODE] 空闲(0):不作为切换请求(退出 RL 请先切关节阻尼或趴下)" << std::endl;
std::cout << "[MODE] idle (0): not treated as a switch request (to exit RL, switch to joint damping or lie down first)" << std::endl;
}
last_request_ = kMotionIdle;
return false;
default:
std::cout << "[MODE] 未知目标状态 " << int(target) << "(来自 " << src << ")" << std::endl;
std::cout << "[MODE] unknown target state " << int(target) << " (from " << src << ")" << std::endl;
return false;
}
@@ -127,9 +127,9 @@ private:
if (accepted) {
usr_cmd_->target_mode = next;
if (last_request_ != target) std::cout << "[MODE] " << name << "(来自 " << src << ")" << std::endl;
if (last_request_ != target) std::cout << "[MODE] " << name << " (from " << src << ")" << std::endl;
} else if (last_request_ != target) {
std::cout << "[MODE] 拒绝 " << name << "(来自 " << src << ",当前状态 " << int(cur) << ")" << std::endl;
std::cout << "[MODE] reject " << name << " (from " << src << ", current state " << int(cur) << ")" << std::endl;
}
last_request_ = target;
return accepted;
@@ -145,14 +145,14 @@ private:
if (gait == 0 || gait == last_gait_request_) return;
// 只有"启动时真的加载了模型"的步态才接受;否则状态会上报未切换,而不是假成功
if (!loaded_gaits_ || loaded_gaits_->count(int(gait)) == 0) {
std::cout << "[GAIT] 拒绝 " << GaitName(gait) << "(来自 " << src
<< "):该步态没有对应的 RL 模型(启动时未加载,见 gait/policy_map)" << std::endl;
std::cout << "[GAIT] reject " << GaitName(gait) << " (from " << src
<< "): this gait has no corresponding RL model (not loaded at startup, see gait/policy_map)" << std::endl;
last_gait_request_ = gait;
return;
}
usr_cmd_->gait = gait;
if (msfb_) msfb_->UpdateCurrentGait(gait);
std::cout << "[GAIT] " << GaitName(gait) << "(来自 " << src << "),实际生效" << std::endl;
std::cout << "[GAIT] " << GaitName(gait) << " (from " << src << "), now effective" << std::endl;
last_gait_request_ = gait;
}
@@ -160,7 +160,7 @@ private:
const std::string src = "invicta_remote";
if (!has_command_) {
has_command_ = true;
std::cout << "[MODE] 收到第一条运动指令(" << topic_ << ")" << std::endl;
std::cout << "[MODE] received first motion command (" << topic_ << ")" << std::endl;
}
// 轴指令:协议里是比例 [-1,1],策略直接用这三个分量
@@ -171,7 +171,7 @@ private:
if (msg->usage_mode != usr_cmd_->usage_mode) {
usr_cmd_->usage_mode = msg->usage_mode;
std::cout << "[MODE] 使用模式 -> " << int(msg->usage_mode) << "(0 常规 / 1 导航 / 2 辅助)" << std::endl;
std::cout << "[MODE] usage mode -> " << int(msg->usage_mode) << " (0 normal / 1 navigation / 2 assist)" << std::endl;
}
RequestMotionState(msg->target_state, src);