Skip to content

Commit f69056c

Browse files
committed
Add lcmt_osc_output; log regularization cost; update log_cassie_plotter accordingly
1 parent 8b0376f commit f69056c

File tree

5 files changed

+167
-41
lines changed

5 files changed

+167
-41
lines changed

bindings/pydairlib/analysis_scripts/log_plotter_cassie.py

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def main():
100100

101101
# Load the main log file
102102
x, u_meas, imu_aceel, t_x, u, t_u, contact_switch, t_contact_switch, contact_info, contact_info_locs, t_contact_info, \
103-
osc_debug, t_osc_debug, fsm, estop_signal, switch_signal, t_controller_switch, t_pd, kp, kd, cassie_out, u_pd, t_u_pd, \
103+
osc_debug, osc_debug_reg_cost, t_osc_debug, fsm, estop_signal, switch_signal, t_controller_switch, t_pd, kp, kd, cassie_out, u_pd, t_u_pd, \
104104
u_dispatcher, t_u_dispatcher, \
105105
osc_output, input_supervisor_status, t_input_supervisor, full_log = process_lcm_log.process_log(log, pos_map, vel_map, act_map, controller_channel)
106106

@@ -198,7 +198,7 @@ def main():
198198
if filename2 != "":
199199
log2 = lcm.EventLog(filename2, "r")
200200
x2, u_meas, imu_aceel, t_x2, u, t_u, contact_switch, t_contact_switch, contact_info, contact_info_locs, t_contact_info, \
201-
osc_debug, t_osc_debug, fsm, estop_signal, switch_signal, t_controller_switch, t_pd, kp, kd, cassie_out, u_pd, t_u_pd, \
201+
osc_debug, osc_debug_reg_cost, t_osc_debug, fsm, estop_signal, switch_signal, t_controller_switch, t_pd, kp, kd, cassie_out, u_pd, t_u_pd, \
202202
u_dispatcher, t_u_dispatcher, \
203203
osc_output, input_supervisor_status, t_input_supervisor, full_log = process_lcm_log.process_log(log2, pos_map, vel_map, act_map, controller_channel)
204204

@@ -665,36 +665,76 @@ def plot_contact_est(log, t_osc_debug, fsm, t_u, u, t_x, x, u_meas):
665665
# plt.legend(["l_contact", "r_contact", "fsm", "pelvis y (%dx)" % y_scale, "pelvis ydot (%dx)" % ydot_scale])
666666

667667

668-
def plot_osc_debug(t_osc_debug, fsm, osc_debug, t_cassie_out, estop_signal, osc_output):
669-
input_cost = np.zeros(t_osc_debug.shape[0])
670-
acceleration_cost = np.zeros(t_osc_debug.shape[0])
671-
soft_constraint_cost = np.zeros(t_osc_debug.shape[0])
672-
tracking_cost = np.zeros((t_osc_debug.shape[0], len(osc_debug)))
668+
def plot_osc_debug(t_osc_debug, fsm, osc_debug, osc_debug_reg_cost, t_cassie_out, estop_signal, osc_output):
669+
"""
670+
1. Plot trajectories
671+
"""
672+
# input_cost = np.zeros(t_osc_debug.shape[0])
673+
# acceleration_cost = np.zeros(t_osc_debug.shape[0])
674+
# soft_constraint_cost = np.zeros(t_osc_debug.shape[0])
675+
tracking_costs = np.zeros((t_osc_debug.shape[0], len(osc_debug)))
673676
tracking_cost_map = dict()
674677
num_tracking_cost = 0
678+
reg_costs = np.zeros((t_osc_debug.shape[0], len(osc_debug_reg_cost)))
679+
reg_cost_map = dict()
680+
num_reg_cost = 0
675681

682+
reg_cost_names = list(osc_debug_reg_cost.keys())
683+
684+
# i is the time index
676685
for i in range(t_osc_debug.shape[0]):
677-
input_cost[i] = osc_output[i].input_cost
678-
acceleration_cost[i] = osc_output[i].acceleration_cost
679-
soft_constraint_cost[i] = osc_output[i].soft_constraint_cost
686+
# input_cost[i] = osc_output[i].input_cost
687+
# acceleration_cost[i] = osc_output[i].acceleration_cost
688+
# soft_constraint_cost[i] = osc_output[i].soft_constraint_cost
680689
for j in range(len(osc_output[i].tracking_data_names)):
681690
name = osc_output[i].tracking_data_names[j]
682-
if osc_output[i].tracking_data_names[j] not in tracking_cost_map:
691+
if name not in tracking_cost_map:
683692
tracking_cost_map[name] = num_tracking_cost
684693
num_tracking_cost += 1
685-
tracking_cost[i, tracking_cost_map[name]] = osc_output[i].tracking_cost[j]
694+
tracking_costs[i, tracking_cost_map[name]] = osc_output[i].tracking_costs[j]
695+
696+
for j in range(len(reg_cost_names)):
697+
name = reg_cost_names[j]
698+
if name not in reg_cost_map:
699+
reg_cost_map[name] = num_reg_cost
700+
num_reg_cost += 1
701+
reg_costs[i, reg_cost_map[name]] = osc_debug_reg_cost[name][i]
686702

687703
for name in tracking_cost_map.keys():
688704
print(name)
689705
print(tracking_cost_map[name])
706+
print("")
707+
for name in reg_cost_map.keys():
708+
print(name)
709+
print(reg_cost_map[name])
710+
711+
# sanity check cost >= 0
712+
tracking_cost_nonnegative = np.all(tracking_costs >= 0, axis=0)
713+
for i in range(len(tracking_cost_nonnegative)):
714+
if not tracking_cost_nonnegative[i]:
715+
print(list(tracking_cost_map.keys())[i], " has negative cost!!!")
716+
reg_cost_nonnegative = np.all(reg_costs >= 0, axis=0)
717+
for i in range(len(reg_cost_nonnegative)):
718+
if not reg_cost_nonnegative[i]:
719+
print(reg_cost_names[i], " has negative cost!!!")
720+
if not np.all(tracking_cost_nonnegative) or not np.all(reg_cost_nonnegative):
721+
raise ValueError("There is a negative cost")
722+
723+
import pdb;pdb.set_trace()
690724

691725
plt.figure("costs")
692-
plt.plot(t_osc_debug[t_osc_debug_slice], input_cost[t_osc_debug_slice])
693-
plt.plot(t_osc_debug[t_osc_debug_slice], acceleration_cost[t_osc_debug_slice])
694-
plt.plot(t_osc_debug[t_osc_debug_slice], soft_constraint_cost[t_osc_debug_slice])
695-
plt.plot(t_osc_debug[t_osc_debug_slice], tracking_cost[t_osc_debug_slice])
696-
plt.legend(['input_cost', 'acceleration_cost', 'soft_constraint_cost'] +
697-
list(tracking_cost_map))
726+
# plt.plot(t_osc_debug[t_osc_debug_slice], input_cost[t_osc_debug_slice])
727+
# plt.plot(t_osc_debug[t_osc_debug_slice], acceleration_cost[t_osc_debug_slice])
728+
# plt.plot(t_osc_debug[t_osc_debug_slice], soft_constraint_cost[t_osc_debug_slice])
729+
plt.plot(t_osc_debug[t_osc_debug_slice], tracking_costs[t_osc_debug_slice])
730+
plt.plot(t_osc_debug[t_osc_debug_slice], reg_costs[t_osc_debug_slice], "--")
731+
# plt.legend(['input_cost', 'acceleration_cost', 'soft_constraint_cost'] +
732+
# list(tracking_cost_map))
733+
plt.legend(list(tracking_cost_map) + list(reg_cost_map))
734+
735+
"""
736+
2. Plot trajectories
737+
"""
698738
osc_traj00 = "swing_ft_traj"
699739
# osc_traj00 = "stance_hip_rpy_traj"
700740
# osc_traj0 = "swing_ft_traj"

bindings/pydairlib/analysis_scripts/process_lcm_log.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def process_log(log, pos_map, vel_map, act_map, controller_channel = ""):
119119
estop_signal = []
120120
switch_signal = []
121121
osc_debug = dict()
122+
osc_debug_reg_cost = dict()
122123
contact_forces = [[], [], [], []] # Allocate space for all 4 point contacts
123124
contact_info_locs = [[], [], [], []]
124125
cassie_out = [] # Cassie out types
@@ -147,7 +148,7 @@ def process_log(log, pos_map, vel_map, act_map, controller_channel = ""):
147148
print("osc_debug_channel_name = " + osc_debug_channel_name)
148149

149150
t_dispatcher_end = -1 # stop reading lcm messages after this time
150-
# t_dispatcher_end = 256.5
151+
# t_dispatcher_end = 74.6
151152

152153
for event in log:
153154
if event.channel not in full_log and event.channel not in unknown_types:
@@ -220,13 +221,19 @@ def process_log(log, pos_map, vel_map, act_map, controller_channel = ""):
220221
# and then rebuild the plotting script.
221222
msg = dairlib.lcmt_osc_output.decode(event.data)
222223
osc_output.append(msg)
224+
t_osc_debug.append(msg.utime / 1e6)
225+
fsm.append(msg.fsm_state)
223226
num_osc_tracking_data = len(msg.tracking_data)
224227
for i in range(num_osc_tracking_data):
225228
if msg.tracking_data[i].name not in osc_debug:
226229
osc_debug[msg.tracking_data[i].name] = lcmt_osc_tracking_data_t()
227230
osc_debug[msg.tracking_data[i].name].append(msg.tracking_data[i], msg.utime / 1e6)
228-
t_osc_debug.append(msg.utime / 1e6)
229-
fsm.append(msg.fsm_state)
231+
num_osc_reg_cost = len(msg.regularization_costs)
232+
for i in range(num_osc_reg_cost):
233+
if msg.regularization_cost_names[i] not in osc_debug_reg_cost:
234+
osc_debug_reg_cost[msg.regularization_cost_names[i]] = [msg.regularization_costs[i]]
235+
osc_debug_reg_cost[msg.regularization_cost_names[i]].append(msg.regularization_costs[i])
236+
# import pdb;pdb.set_trace()
230237
if event.channel == "CASSIE_ACCELERATION":
231238
msg = dairlib.lcmt_timestamped_vector.decode(event.data)
232239
vdot.append(msg.data)
@@ -315,10 +322,12 @@ def process_log(log, pos_map, vel_map, act_map, controller_channel = ""):
315322

316323
for key in osc_debug:
317324
osc_debug[key].convertToNP()
325+
for key in osc_debug_reg_cost:
326+
osc_debug_reg_cost[key] = np.array(osc_debug_reg_cost[key])
318327

319328
x = np.hstack((q, v)) # combine into state vector
320329

321330
return x, u_meas, imu_aceel, t_x, u, t_u, contact_switch, t_contact_switch, contact_forces, contact_info_locs, \
322-
t_contact_info, osc_debug, t_osc_debug, fsm, estop_signal, \
331+
t_contact_info, osc_debug, osc_debug_reg_cost, t_osc_debug, fsm, estop_signal, \
323332
switch_signal, t_controller_switch, t_pd, kp, kd, cassie_out, u_pd, \
324333
t_u_pd, u_dispatcher, t_u_dispatcher, osc_output, input_supervisor_status, t_input_supervisor, full_log

lcmtypes/lcmt_osc_output.lcm

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/*
2+
Before 20221122:
3+
14
package dairlib;
25

36
struct lcmt_osc_output
@@ -15,3 +18,22 @@ struct lcmt_osc_output
1518
double soft_constraint_cost;
1619
double tracking_cost [num_tracking_data];
1720
}
21+
*/
22+
23+
package dairlib;
24+
25+
struct lcmt_osc_output
26+
{
27+
int64_t utime;
28+
int32_t fsm_state;
29+
int32_t num_tracking_data;
30+
int32_t num_regularization_costs;
31+
32+
lcmt_osc_qp_output qp_output;
33+
string tracking_data_names[num_tracking_data];
34+
double tracking_costs [num_tracking_data];
35+
double regularization_costs [num_regularization_costs];
36+
string regularization_cost_names [num_regularization_costs];
37+
38+
lcmt_osc_tracking_data tracking_data[num_tracking_data];
39+
}

systems/controllers/osc/operational_space_control.cc

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,11 @@ void OperationalSpaceControl::Build() {
492492
/// hard constraint version
493493
prog_->AddBoundingBoxConstraint(0, 0, epsilon_blend_);
494494
}
495+
495496
// Testing -- penalize the front contact for optimal model as a regularization
496497
// term, in order to help the solver to find good solution.
497498
if (w_rom_force_reg_ > 0) {
498-
contact_force_reg_cost_ =
499+
front_contact_force_reg_cost_ =
499500
prog_
500501
->AddQuadraticCost(
501502
w_rom_force_reg_ * MatrixXd::Identity(2, 2), VectorXd::Zero(2),
@@ -928,25 +929,36 @@ VectorXd OperationalSpaceControl::SolveQp(
928929
}
929930

930931
// (Testing) 7. Cost for staying close to the previous input
931-
if (w_input_reg_ > 0) {
932-
input_reg_cost_->UpdateCoefficients(W_input_reg_,
933-
-W_input_reg_ * (*u_sol_));
932+
if (W_input_reg_.size() > 0) {
933+
// input_reg_cost_->UpdateCoefficients(W_input_reg_,
934+
// -W_input_reg_ * (*u_sol_));
935+
input_reg_cost_->UpdateCoefficients(
936+
W_input_reg_, -W_input_reg_ * (*u_sol_),
937+
0.5 * u_sol_->transpose() * W_input_reg_ * (*u_sol_));
934938
}
935939
// (Testing) Cost for staying close to the previous solution
936940
if (W_lambda_c_reg_.size() > 0) {
937941
// lambda_c_cost_->UpdateCoefficients(W_lambda_c_reg_,
938-
// VectorXd::Zero(n_c_));
939-
lambda_c_cost_->UpdateCoefficients(W_lambda_c_reg_,
940-
-W_lambda_c_reg_ * (*lambda_c_sol_));
942+
// -W_lambda_c_reg_ *
943+
// (*lambda_c_sol_));
944+
lambda_c_cost_->UpdateCoefficients(
945+
W_lambda_c_reg_, -W_lambda_c_reg_ * (*lambda_c_sol_),
946+
0.5 * lambda_c_sol_->transpose() * W_lambda_c_reg_ * (*lambda_c_sol_));
941947
}
942948
if (W_lambda_h_reg_.size() > 0) {
943949
// lambda_h_cost_->UpdateCoefficients(W_lambda_h_reg_,
944-
// VectorXd::Zero(n_h_));
945-
lambda_h_cost_->UpdateCoefficients(W_lambda_h_reg_,
946-
-W_lambda_h_reg_ * (*lambda_h_sol_));
950+
// -W_lambda_h_reg_ *
951+
// (*lambda_h_sol_));
952+
lambda_h_cost_->UpdateCoefficients(
953+
W_lambda_h_reg_, -W_lambda_h_reg_ * (*lambda_h_sol_),
954+
0.5 * lambda_h_sol_->transpose() * W_lambda_h_reg_ * (*lambda_h_sol_));
947955
}
948956
if (W_vdot_reg_.size() > 0) {
949-
vdot_reg_cost_->UpdateCoefficients(W_vdot_reg_, -W_vdot_reg_ * (*dv_sol_));
957+
// vdot_reg_cost_->UpdateCoefficients(W_vdot_reg_, -W_vdot_reg_ *
958+
// (*dv_sol_));
959+
vdot_reg_cost_->UpdateCoefficients(
960+
W_vdot_reg_, -W_vdot_reg_ * (*dv_sol_),
961+
0.5 * dv_sol_->transpose() * W_vdot_reg_ * (*dv_sol_));
950962
}
951963

952964
if (is_rom_modification_) {
@@ -1120,23 +1132,65 @@ void OperationalSpaceControl::AssignOscLcmOutput(
11201132

11211133
output->utime = state->get_timestamp() * 1e6;
11221134
output->fsm_state = fsm_state;
1123-
output->input_cost =
1135+
double input_cost =
11241136
(W_input_.size() > 0)
11251137
? (0.5 * (*u_sol_).transpose() * W_input_ * (*u_sol_))(0)
11261138
: 0;
1127-
output->acceleration_cost =
1139+
double acceleration_cost =
11281140
(W_joint_accel_.size() > 0)
11291141
? (0.5 * (*dv_sol_).transpose() * W_joint_accel_ * (*dv_sol_))(0)
11301142
: 0;
1131-
output->soft_constraint_cost =
1143+
double soft_constraint_cost =
11321144
(w_soft_constraint_ > 0)
11331145
? (0.5 * w_soft_constraint_ * (*epsilon_sol_).transpose() *
11341146
(*epsilon_sol_))(0)
11351147
: 0;
1148+
VectorXd y_input_reg_cost = VectorXd::Zero(1);
1149+
VectorXd y_lambda_c_cost = VectorXd::Zero(1);
1150+
VectorXd y_lambda_h_cost = VectorXd::Zero(1);
1151+
VectorXd y_vdot_reg_cost = VectorXd::Zero(1);
1152+
VectorXd y_front_contact_force_reg_cost = VectorXd::Zero(1);
1153+
if (input_reg_cost_) {
1154+
input_reg_cost_->Eval(*u_sol_, &y_input_reg_cost);
1155+
}
1156+
if (lambda_c_cost_) {
1157+
lambda_c_cost_->Eval(*lambda_c_sol_, &y_lambda_c_cost);
1158+
}
1159+
if (lambda_h_cost_) {
1160+
lambda_h_cost_->Eval(*lambda_h_sol_, &y_lambda_h_cost);
1161+
}
1162+
if (vdot_reg_cost_) {
1163+
vdot_reg_cost_->Eval(*dv_sol_, &y_vdot_reg_cost);
1164+
}
1165+
if (front_contact_force_reg_cost_) {
1166+
VectorXd input(2);
1167+
input << lambda_c_sol_->segment<1>(2), lambda_c_sol_->segment<1>(8);
1168+
front_contact_force_reg_cost_->Eval(input, &y_front_contact_force_reg_cost);
1169+
}
1170+
1171+
output->regularization_costs.clear();
1172+
output->regularization_cost_names.clear();
1173+
1174+
output->regularization_costs.push_back(input_cost);
1175+
output->regularization_cost_names.push_back("input_cost");
1176+
output->regularization_costs.push_back(acceleration_cost);
1177+
output->regularization_cost_names.push_back("acceleration_cost");
1178+
output->regularization_costs.push_back(soft_constraint_cost);
1179+
output->regularization_cost_names.push_back("soft_constraint_cost");
1180+
output->regularization_costs.push_back(y_input_reg_cost[0]);
1181+
output->regularization_cost_names.push_back("input_reg_cost");
1182+
output->regularization_costs.push_back(y_lambda_c_cost[0]);
1183+
output->regularization_cost_names.push_back("lambda_c_cost");
1184+
output->regularization_costs.push_back(y_lambda_h_cost[0]);
1185+
output->regularization_cost_names.push_back("lambda_h_cost");
1186+
output->regularization_costs.push_back(y_vdot_reg_cost[0]);
1187+
output->regularization_cost_names.push_back("vdot_reg_cost");
1188+
output->regularization_costs.push_back(y_front_contact_force_reg_cost[0]);
1189+
output->regularization_cost_names.push_back("front_contact_force_reg_cost");
11361190

11371191
output->tracking_data_names.clear();
11381192
output->tracking_data.clear();
1139-
output->tracking_cost.clear();
1193+
output->tracking_costs.clear();
11401194

11411195
lcmt_osc_qp_output qp_output;
11421196
qp_output.solve_time = solve_time_;
@@ -1153,7 +1207,7 @@ void OperationalSpaceControl::AssignOscLcmOutput(
11531207
output->qp_output = qp_output;
11541208

11551209
output->tracking_data.reserve(tracking_data_vec_->size());
1156-
output->tracking_cost.reserve(tracking_data_vec_->size());
1210+
output->tracking_costs.reserve(tracking_data_vec_->size());
11571211

11581212
for (unsigned int i = 0; i < tracking_data_vec_->size(); i++) {
11591213
auto tracking_data = tracking_data_vec_->at(i);
@@ -1188,13 +1242,14 @@ void OperationalSpaceControl::AssignOscLcmOutput(
11881242
const MatrixXd& W = tracking_data->GetWeight();
11891243
const MatrixXd& J_t = tracking_data->GetJ();
11901244
const VectorXd& JdotV_t = tracking_data->GetJdotTimesV();
1191-
output->tracking_cost.push_back(
1245+
output->tracking_costs.push_back(
11921246
(0.5 * (J_t * (*dv_sol_) + JdotV_t - ddy_t).transpose() * W *
11931247
(J_t * (*dv_sol_) + JdotV_t - ddy_t))(0));
11941248
}
11951249
}
11961250

11971251
output->num_tracking_data = output->tracking_data_names.size();
1252+
output->num_regularization_costs = output->regularization_cost_names.size();
11981253
}
11991254

12001255
void OperationalSpaceControl::CalcOptimalInput(

systems/controllers/osc/operational_space_control.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ class OperationalSpaceControl : public drake::systems::LeafSystem<double> {
399399
drake::solvers::VectorXDecisionVariable epsilon_blend_;
400400

401401
// Optional feature -- regularizing input
402-
drake::solvers::QuadraticCost* input_reg_cost_;
402+
drake::solvers::QuadraticCost* input_reg_cost_ = nullptr;
403403
double w_input_reg_ = -1;
404404
Eigen::MatrixXd W_input_reg_;
405405

@@ -415,7 +415,7 @@ class OperationalSpaceControl : public drake::systems::LeafSystem<double> {
415415
// (penalize the front contact for optimal model as a regularization term, in
416416
// order to help the solver to find good solution.)
417417
double w_rom_force_reg_ = -1;
418-
drake::solvers::QuadraticCost* contact_force_reg_cost_;
418+
drake::solvers::QuadraticCost* front_contact_force_reg_cost_ = nullptr;
419419
};
420420

421421
} // namespace dairlib::systems::controllers

0 commit comments

Comments
 (0)