Skip to content

Commit 56c5edb

Browse files
Merge pull request #27 from nasa-jpl/add-actuator-power-dev
Add actuator power dev
2 parents d15eaa4 + bd30242 commit 56c5edb

7 files changed

+86
-2
lines changed

doc/fastcat_device_config_parameters.md

+3
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ Engineering Units (EU) are radians for revolute actuators and meters for linear
188188
| `egd_crc` | CRC of the flashed Elmo parameter set |
189189
| `egd_drive_max_current_limit` | The Maximum drive current for the Elmo Gold Drive |
190190
| `smooth_factor` | Affects controller smoothing, defaults to `0` |
191+
| `winding_resistance` | OPTIONAL: Winding resistance of motor for optional power calculation |
192+
| `torque_constant` | OPTIONAL: Torque constant of motor for optional power calculation |
193+
| `motor_encoder_gear_ratio` | OPTIONAL: Capture any gear ratio between the motor and the encoder, i.e. an output encoder |
191194

192195
### Implementation Notes
193196

src/fcgen/fastcat_types.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ states:
118118
type: int32_t
119119
- name: actuator_state_machine_state
120120
type: uint8_t
121+
- name: power
122+
type: double
121123

122124
- name: faulter
123125
fields:

src/jsd/actuator.cc

+35
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,25 @@ bool fastcat::Actuator::ConfigFromYaml(YAML::Node node)
132132
if (!ParseValCheckRange(node, "smooth_factor", smooth_factor_, -1, 64)) {
133133
return false;
134134
}
135+
136+
if (ParseOptValCheckRange(node, "torque_constant", torque_constant_, 0.0, 999999.0) &&
137+
ParseOptValCheckRange(node, "winding_resistance", winding_resistance_, 0.0, 999999.0) ) {
138+
139+
// Only compute power if we received both torque_constant and winding_resistance parameters
140+
compute_power_ = true;
141+
142+
// Read in brake power (if provided) to add to actuator power
143+
if (!ParseOptValCheckRange(node, "brake_power", brake_power_, 0.0, 9999.0)) {
144+
// If not found then set to zero
145+
brake_power_ = 0.0;
146+
}
147+
148+
// Read in any gear ratio between the motor and encoder for power calculation
149+
if (!ParseOptValCheckRange(node, "motor_encoder_gear_ratio", motor_encoder_gear_ratio_, 0.0, 9999.0)) {
150+
// If not found then set to 1.0
151+
motor_encoder_gear_ratio_ = 1.0;
152+
}
153+
}
135154

136155
// overall_reduction must be set before using EuToCnts/CntsToEu
137156
if (actuator_type_ == ACTUATOR_TYPE_REVOLUTE) {
@@ -221,6 +240,22 @@ bool fastcat::Actuator::Read()
221240
state_->actuator_state.actuator_state_machine_state =
222241
static_cast<int>(actuator_sms_);
223242

243+
if (compute_power_) {
244+
double motor_velocity = fabs(state_->actuator_state.actual_velocity) * motor_encoder_gear_ratio_;
245+
double current = fabs(jsd_egd_state_.actual_current);
246+
247+
// P = R I^2 + K_T * I * \omega
248+
state_->actuator_state.power = current *
249+
(winding_resistance_ * current +
250+
torque_constant_ * motor_velocity);
251+
252+
// Should checking, but assuming motor_on > 0 means brakes powered/disengaged
253+
if (state_->actuator_state.motor_on)
254+
state_->actuator_state.power += brake_power_;
255+
}
256+
// else
257+
// state_->actuator_state.power = 0;
258+
224259
return true;
225260
}
226261

src/jsd/actuator.h

+6
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ class Actuator : public DeviceBase
119119
double egd_crc_ = 0;
120120
double egd_drive_max_cur_limit_amps_ = 0;
121121
double smooth_factor_ = 0;
122+
double torque_constant_ = 0;
123+
double winding_resistance_ = 0;
124+
double brake_power_ = 0;
125+
double motor_encoder_gear_ratio_ = 0;
126+
127+
bool compute_power_ = false;
122128

123129
jsd_slave_config_t jsd_slave_config_;
124130
jsd_egd_state_t jsd_egd_state_;

src/jsd/actuator_offline.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,17 @@ void fastcat::ActuatorOffline::EgdCSP(jsd_egd_motion_command_csp_t jsd_csp_cmd)
6161
jsd_egd_state_.cmd_ff_velocity = jsd_csp_cmd.velocity_offset;
6262
jsd_egd_state_.cmd_ff_current = jsd_csp_cmd.torque_offset_amps;
6363

64+
// Differentiate position to get actual_velocity
65+
double vel = (jsd_egd_state_.cmd_position + jsd_egd_state_.cmd_ff_position
66+
- jsd_egd_state_.actual_position) / loop_period_;
67+
6468
// simulate actuals
6569
jsd_egd_state_.actual_position =
6670
jsd_egd_state_.cmd_position + jsd_egd_state_.cmd_ff_position;
67-
jsd_egd_state_.actual_velocity =
68-
jsd_egd_state_.cmd_velocity + jsd_egd_state_.cmd_ff_velocity;
6971
jsd_egd_state_.actual_current =
7072
jsd_egd_state_.cmd_current + jsd_egd_state_.cmd_ff_current;
73+
74+
jsd_egd_state_.actual_velocity = vel; // "sure, why not"
7175
}
7276

7377
void fastcat::ActuatorOffline::EgdCSV(jsd_egd_motion_command_csv_t jsd_csv_cmd)

src/yaml_parser.cc

+28
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,31 @@ bool fastcat::ParseValCheckRange(YAML::Node node, std::string field,
262262
upper);
263263
return false;
264264
}
265+
266+
// Optional value parsing
267+
268+
bool fastcat::ParseOptVal(YAML::Node node, std::string field, double& val)
269+
{
270+
if (!node[field]) {
271+
MSG_DEBUG("Did not find optional double field: %s", field.c_str());
272+
return false;
273+
}
274+
val = node[field].as<double>();
275+
MSG_DEBUG("Parsed double field %s: %lf", field.c_str(), val);
276+
return true;
277+
}
278+
279+
bool fastcat::ParseOptValCheckRange(YAML::Node node, std::string field,
280+
double& val, double lower, double upper)
281+
{
282+
if (!ParseOptVal(node, field, val)) {
283+
return false;
284+
}
285+
286+
if (lower <= val && val <= upper) {
287+
return true;
288+
}
289+
ERROR("%s failed range check %lf <= %lf <= %lf", field.c_str(), lower, val,
290+
upper);
291+
return false;
292+
}

src/yaml_parser.h

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ bool ParseValCheckRange(YAML::Node node, std::string field, int8_t& val,
5050
bool ParseValCheckRange(YAML::Node node, std::string field, uint8_t& val,
5151
uint8_t lower, uint8_t upper);
5252

53+
// Optional double values
54+
bool ParseOptVal(YAML::Node node, std::string field, double& val);
55+
56+
bool ParseOptValCheckRange(YAML::Node node, std::string field, double& val,
57+
double lower, double upper);
58+
5359
} // namespace fastcat
5460

5561
#endif

0 commit comments

Comments
 (0)