Skip to content
This repository was archived by the owner on Dec 1, 2020. It is now read-only.

Commit 04fda05

Browse files
author
Olav de Haas
committed
Merge branch 'develop' into feature/PM-325-ethercat-interface
2 parents 6589140 + 3c78721 commit 04fda05

File tree

21 files changed

+649
-533
lines changed

21 files changed

+649
-533
lines changed

march_hardware/include/march_hardware/IMotionCube.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ class IMotionCube : public Slave
4949
int16_t getTorque();
5050
int32_t getAngleIUAbsolute();
5151
int32_t getAngleIUIncremental();
52+
double getVelocityIUAbsolute();
53+
double getVelocityIUIncremental();
54+
virtual double getVelocityRadAbsolute();
55+
virtual double getVelocityRadIncremental();
5256

5357
uint16_t getStatusWord();
5458
uint16_t getMotionError();

march_hardware/include/march_hardware/IMotionCubeState.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ struct IMotionCubeState
134134
float IMCVoltage;
135135
int absoluteEncoderValue;
136136
int incrementalEncoderValue;
137+
double absoluteVelocity;
138+
double incrementalVelocity;
137139
};
138140

139141
} // namespace march

march_hardware/include/march_hardware/Joint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class Joint
6060
int16_t getTorque();
6161
int32_t getAngleIUAbsolute();
6262
int32_t getAngleIUIncremental();
63+
double getVelocityIUAbsolute();
64+
double getVelocityIUIncremental();
6365
float getTemperature();
6466
IMotionCubeState getIMotionCubeState();
6567

@@ -127,6 +129,8 @@ class Joint
127129
float previous_motor_current_ = 0.0;
128130
double previous_absolute_position_ = 0.0;
129131
double previous_incremental_position_ = 0.0;
132+
double previous_absolute_velocity_ = 0.0;
133+
double previous_incremental_velocity_ = 0.0;
130134

131135
double position_ = 0.0;
132136
double incremental_position_ = 0.0;

march_hardware/include/march_hardware/PDOmap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ enum class IMCObjectName
4242
{
4343
StatusWord,
4444
ActualPosition,
45+
ActualVelocity,
4546
MotionErrorRegister,
4647
DetailedErrorRegister,
4748
DCLinkVoltage,
4849
DriveTemperature,
4950
ActualTorque,
5051
CurrentLimit,
5152
MotorPosition,
53+
MotorVelocity,
5254
ControlWord,
5355
TargetPosition,
5456
TargetTorque,

march_hardware/include/march_hardware/encoder/Encoder.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ class Encoder
3333
*/
3434
double getAngleRad(const PdoSlaveInterface& pdo, uint8_t byte_offset) const;
3535

36+
/**
37+
* Reads out the velocity of the encoder from the slave and returns the value in Internal Units per second (IU/s).
38+
* @param pdo PDO interface to use for reading
39+
* @param byte_offset the byte offset in the slave register for the IU velocity
40+
* @returns The current velocity measured by the encoder in Internal Units per second (IU/s)
41+
*/
42+
double getVelocityIU(const PdoSlaveInterface& pdo, uint8_t byte_offset) const;
43+
44+
/**
45+
* Reads out the velocity of the encoder from the slave and transforms the result to radians per second.
46+
* @param pdo PDO interface to use for reading
47+
* @param byte_offset the byte offset in the slave register for the IU velocity
48+
* @returns The current velocity measured by the encoder in radians per second
49+
*/
50+
double getVelocityRad(const PdoSlaveInterface& pdo, uint8_t byte_offset) const;
51+
3652
/**
3753
* Converts encoder Internal Units (IU) to radians.
3854
* This is a pure virtual function and must be implemented by subclasses,
@@ -52,6 +68,12 @@ class Encoder
5268
static const size_t MIN_RESOLUTION = 1;
5369
static const size_t MAX_RESOLUTION = 32;
5470

71+
// constant used for converting a fixed point 16.16 bit number to a double, which is done by dividing by 2^16
72+
static constexpr double FIXED_POINT_TO_FLOAT_CONVERSION = 1 << 16;
73+
74+
// iMOTIONCUBE setting (slow loop sample period)
75+
static constexpr double TIME_PER_VELOCITY_SAMPLE = 0.004;
76+
5577
static constexpr double PI_2 = 2 * M_PI;
5678

5779
private:

march_hardware/src/IMotionCube.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ void IMotionCube::mapMisoPDOs(SdoSlaveInterface& sdo)
6363
map_miso.addObject(IMCObjectName::DetailedErrorRegister);
6464
map_miso.addObject(IMCObjectName::DCLinkVoltage);
6565
map_miso.addObject(IMCObjectName::MotorPosition);
66+
map_miso.addObject(IMCObjectName::MotorVelocity);
67+
map_miso.addObject(IMCObjectName::ActualVelocity);
6668
this->miso_byte_offsets_ = map_miso.map(sdo, DataDirection::MISO);
6769
}
6870

@@ -237,6 +239,26 @@ int IMotionCube::getAngleIUIncremental()
237239
return this->incremental_encoder_->getAngleIU(*this, this->miso_byte_offsets_.at(IMCObjectName::MotorPosition));
238240
}
239241

242+
double IMotionCube::getVelocityIUAbsolute()
243+
{
244+
return this->absolute_encoder_->getVelocityIU(*this, this->miso_byte_offsets_.at(IMCObjectName::ActualVelocity));
245+
}
246+
247+
double IMotionCube::getVelocityIUIncremental()
248+
{
249+
return this->incremental_encoder_->getVelocityIU(*this, this->miso_byte_offsets_.at(IMCObjectName::MotorVelocity));
250+
}
251+
252+
double IMotionCube::getVelocityRadAbsolute()
253+
{
254+
return this->absolute_encoder_->getVelocityRad(*this, this->miso_byte_offsets_.at(IMCObjectName::ActualVelocity));
255+
}
256+
257+
double IMotionCube::getVelocityRadIncremental()
258+
{
259+
return this->incremental_encoder_->getVelocityRad(*this, this->miso_byte_offsets_.at(IMCObjectName::MotorVelocity));
260+
}
261+
240262
uint16_t IMotionCube::getStatusWord()
241263
{
242264
return this->read16(this->miso_byte_offsets_.at(IMCObjectName::StatusWord)).ui;

march_hardware/src/Joint.cpp

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -96,27 +96,21 @@ void Joint::readEncoders(const ros::Duration& elapsed_time)
9696

9797
if (this->receivedDataUpdate())
9898
{
99-
const double new_incremental_position = this->imc_->getAngleRadIncremental();
100-
const double new_absolute_position = this->imc_->getAngleRadAbsolute();
99+
const double incremental_position_change = this->imc_->getAngleRadIncremental() - this->incremental_position_;
101100

102-
// Get velocity from encoder position
103-
double best_displacement;
104-
105-
// Take the velocity with the highest resolution.
101+
// Take the velocity and position from the encoder with the highest resolution.
106102
if (this->imc_->getIncrementalRadPerBit() < this->imc_->getAbsoluteRadPerBit())
107103
{
108-
best_displacement = new_incremental_position - this->incremental_position_;
104+
this->velocity_ = this->imc_->getVelocityRadIncremental();
105+
this->position_ += incremental_position_change;
109106
}
110107
else
111108
{
112-
best_displacement = new_absolute_position - this->absolute_position_;
109+
this->velocity_ = this->imc_->getVelocityRadAbsolute();
110+
this->position_ = this->imc_->getAngleRadAbsolute();
113111
}
114-
115-
// Update position with the most accurate velocity
116-
this->position_ += best_displacement;
117-
this->velocity_ = best_displacement / elapsed_time.toSec();
118-
this->incremental_position_ = new_incremental_position;
119-
this->absolute_position_ = new_absolute_position;
112+
this->incremental_position_ += incremental_position_change;
113+
this->absolute_position_ = this->imc_->getAngleRadAbsolute();
120114
}
121115
else
122116
{
@@ -187,6 +181,26 @@ int32_t Joint::getAngleIUIncremental()
187181
return this->imc_->getAngleIUIncremental();
188182
}
189183

184+
double Joint::getVelocityIUAbsolute()
185+
{
186+
if (!this->hasIMotionCube())
187+
{
188+
ROS_WARN("[%s] Has no iMotionCube", this->name_.c_str());
189+
return -1;
190+
}
191+
return this->imc_->getVelocityIUAbsolute();
192+
}
193+
194+
double Joint::getVelocityIUIncremental()
195+
{
196+
if (!this->hasIMotionCube())
197+
{
198+
ROS_WARN("[%s] Has no iMotionCube", this->name_.c_str());
199+
return -1;
200+
}
201+
return this->imc_->getVelocityIUIncremental();
202+
}
203+
190204
float Joint::getTemperature()
191205
{
192206
if (!this->hasTemperatureGES())
@@ -217,6 +231,8 @@ IMotionCubeState Joint::getIMotionCubeState()
217231

218232
states.absoluteEncoderValue = this->imc_->getAngleIUAbsolute();
219233
states.incrementalEncoderValue = this->imc_->getAngleIUIncremental();
234+
states.absoluteVelocity = this->imc_->getVelocityIUAbsolute();
235+
states.incrementalVelocity = this->imc_->getVelocityIUIncremental();
220236

221237
return states;
222238
}
@@ -275,19 +291,27 @@ bool Joint::receivedDataUpdate()
275291
{
276292
return false;
277293
}
278-
// If imc voltage, motor current, and both encoders positions did not change,
294+
// If imc voltage, motor current, and both encoders positions and velocities did not change,
279295
// we probably did not receive an update for this joint.
280296
float new_imc_volt = this->imc_->getIMCVoltage();
281297
float new_motor_current = this->imc_->getMotorCurrent();
282298
double new_absolute_position = this->imc_->getAngleRadAbsolute();
283299
double new_incremental_position = this->imc_->getAngleRadIncremental();
300+
double new_absolute_velocity = this->imc_->getVelocityRadAbsolute();
301+
double new_incremental_velocity = this->imc_->getVelocityRadIncremental();
302+
284303
bool data_updated = (new_imc_volt != this->previous_imc_volt_ || new_motor_current != this->previous_motor_current_ ||
285304
new_absolute_position != this->previous_absolute_position_ ||
286-
new_incremental_position != this->previous_incremental_position_);
305+
new_incremental_position != this->previous_incremental_position_ ||
306+
new_absolute_velocity != this->previous_absolute_velocity_ ||
307+
new_incremental_velocity != this->previous_incremental_velocity_);
308+
287309
this->previous_imc_volt_ = new_imc_volt;
288310
this->previous_motor_current_ = new_motor_current;
289311
this->previous_absolute_position_ = new_absolute_position;
290312
this->previous_incremental_position_ = new_incremental_position;
313+
this->previous_absolute_velocity_ = new_absolute_velocity;
314+
this->previous_incremental_velocity_ = new_incremental_velocity;
291315
return data_updated;
292316
}
293317

march_hardware/src/PDOmap.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ namespace march
1212
std::unordered_map<IMCObjectName, IMCObject> PDOmap::all_objects = {
1313
{ IMCObjectName::StatusWord, IMCObject(0x6041, 16) },
1414
{ IMCObjectName::ActualPosition, IMCObject(0x6064, 32) },
15+
{ IMCObjectName::ActualVelocity, IMCObject(0x6069, 32) },
1516
{ IMCObjectName::MotionErrorRegister, IMCObject(0x2000, 16) },
1617
{ IMCObjectName::DetailedErrorRegister, IMCObject(0x2002, 16) },
1718
{ IMCObjectName::DCLinkVoltage, IMCObject(0x2055, 16) },
1819
{ IMCObjectName::DriveTemperature, IMCObject(0x2058, 16) },
1920
{ IMCObjectName::ActualTorque, IMCObject(0x6077, 16) },
2021
{ IMCObjectName::CurrentLimit, IMCObject(0x207F, 16) },
2122
{ IMCObjectName::MotorPosition, IMCObject(0x2088, 32) },
23+
{ IMCObjectName::MotorVelocity, IMCObject(0x2087, 32) },
2224
{ IMCObjectName::ControlWord, IMCObject(0x6040, 16) },
2325
{ IMCObjectName::TargetPosition, IMCObject(0x607A, 32) },
2426
{ IMCObjectName::TargetTorque, IMCObject(0x6071, 16) },

march_hardware/src/encoder/Encoder.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ double Encoder::getAngleRad(const PdoSlaveInterface& pdo, uint8_t byte_offset) c
2020
return this->toRad(this->getAngleIU(pdo, byte_offset));
2121
}
2222

23+
double Encoder::getVelocityIU(const PdoSlaveInterface& pdo, uint8_t byte_offset) const
24+
{
25+
bit32 return_byte = pdo.read32(byte_offset);
26+
return return_byte.i / (TIME_PER_VELOCITY_SAMPLE * FIXED_POINT_TO_FLOAT_CONVERSION);
27+
}
28+
29+
double Encoder::getVelocityRad(const PdoSlaveInterface& pdo, uint8_t byte_offset) const
30+
{
31+
return this->getVelocityIU(pdo, byte_offset) * this->getRadPerBit();
32+
}
33+
2334
size_t Encoder::getTotalPositions() const
2435
{
2536
return this->total_positions_;

march_hardware/test/TestJoint.cpp

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,13 @@ TEST_F(JointTest, TestReadEncodersOnce)
203203
{
204204
ros::Duration elapsed_time(0.2);
205205
double velocity = 0.5;
206-
double absolute_noise = -2 * this->imc->getAbsoluteRadPerBit();
206+
double velocity_with_noise = velocity - 2 * this->imc->getAbsoluteRadPerBit() / elapsed_time.toSec();
207207

208208
double initial_incremental_position = 5;
209209
double initial_absolute_position = 3;
210+
210211
double new_incremental_position = initial_incremental_position + velocity * elapsed_time.toSec();
211-
double new_absolute_position = initial_absolute_position + velocity * elapsed_time.toSec() + absolute_noise;
212+
double new_absolute_position = initial_absolute_position + velocity_with_noise * elapsed_time.toSec();
212213

213214
EXPECT_CALL(*this->imc, getIMCVoltage()).WillOnce(Return(48));
214215
EXPECT_CALL(*this->imc, getMotorCurrent()).WillOnce(Return(5));
@@ -221,14 +222,17 @@ TEST_F(JointTest, TestReadEncodersOnce)
221222
.WillOnce(Return(new_absolute_position))
222223
.WillOnce(Return(new_absolute_position));
223224

225+
EXPECT_CALL(*this->imc, getVelocityRadIncremental()).WillOnce(Return(velocity)).WillOnce(Return(velocity));
226+
EXPECT_CALL(*this->imc, getVelocityRadAbsolute()).WillOnce(Return(velocity_with_noise));
227+
224228
march::Joint joint("actuate_true", 0, true, std::move(this->imc));
225229
joint.prepareActuation();
226230

227231
joint.readEncoders(elapsed_time);
228232

229233
ASSERT_DOUBLE_EQ(joint.getPosition(), initial_absolute_position + velocity * elapsed_time.toSec());
230-
ASSERT_DOUBLE_EQ(joint.getVelocity(),
231-
(new_incremental_position - initial_incremental_position) / elapsed_time.toSec());
234+
ASSERT_NEAR(joint.getVelocity(), (new_incremental_position - initial_incremental_position) / elapsed_time.toSec(),
235+
0.0000001);
232236
}
233237

234238
TEST_F(JointTest, TestReadEncodersTwice)
@@ -238,13 +242,15 @@ TEST_F(JointTest, TestReadEncodersTwice)
238242
double second_velocity = 0.8;
239243

240244
double absolute_noise = -this->imc->getAbsoluteRadPerBit();
245+
double first_velocity_with_noise = first_velocity + absolute_noise / elapsed_time.toSec();
246+
double second_velocity_with_noise = second_velocity + absolute_noise / elapsed_time.toSec();
241247

242248
double initial_incremental_position = 5;
243249
double initial_absolute_position = 3;
244250
double second_incremental_position = initial_incremental_position + first_velocity * elapsed_time.toSec();
245-
double second_absolute_position = initial_absolute_position + first_velocity * elapsed_time.toSec() + absolute_noise;
251+
double second_absolute_position = initial_absolute_position + first_velocity * elapsed_time.toSec();
246252
double third_incremental_position = second_incremental_position + second_velocity * elapsed_time.toSec();
247-
double third_absolute_position = second_absolute_position + second_velocity * elapsed_time.toSec() + absolute_noise;
253+
double third_absolute_position = second_absolute_position + second_velocity_with_noise * elapsed_time.toSec();
248254

249255
EXPECT_CALL(*this->imc, getIMCVoltage()).WillOnce(Return(48)).WillOnce(Return(48.01));
250256
EXPECT_CALL(*this->imc, getAngleRadIncremental())
@@ -259,6 +265,14 @@ TEST_F(JointTest, TestReadEncodersTwice)
259265
.WillOnce(Return(second_absolute_position))
260266
.WillOnce(Return(third_absolute_position))
261267
.WillOnce(Return(third_absolute_position));
268+
EXPECT_CALL(*this->imc, getVelocityRadIncremental())
269+
.WillOnce(Return(first_velocity))
270+
.WillOnce(Return(first_velocity))
271+
.WillOnce(Return(second_velocity))
272+
.WillOnce(Return(second_velocity));
273+
EXPECT_CALL(*this->imc, getVelocityRadAbsolute())
274+
.WillOnce(Return(first_velocity_with_noise))
275+
.WillOnce(Return(second_velocity_with_noise));
262276

263277
march::Joint joint("actuate_true", 0, true, std::move(this->imc));
264278
joint.prepareActuation();
@@ -268,21 +282,22 @@ TEST_F(JointTest, TestReadEncodersTwice)
268282

269283
ASSERT_DOUBLE_EQ(joint.getPosition(),
270284
initial_absolute_position + (first_velocity + second_velocity) * elapsed_time.toSec());
271-
ASSERT_DOUBLE_EQ(joint.getVelocity(),
272-
(third_incremental_position - second_incremental_position) / elapsed_time.toSec());
285+
ASSERT_NEAR(joint.getVelocity(), (third_incremental_position - second_incremental_position) / elapsed_time.toSec(),
286+
0.0000001);
273287
}
274288

275289
TEST_F(JointTest, TestReadEncodersNoUpdate)
276290
{
277291
ros::Duration elapsed_time(0.2);
278-
double first_velocity = 0.5;
292+
293+
double velocity = 0.5;
279294

280295
double absolute_noise = -this->imc->getAbsoluteRadPerBit();
281296

282297
double initial_incremental_position = 5;
283298
double initial_absolute_position = 3;
284-
double second_incremental_position = initial_incremental_position + first_velocity * elapsed_time.toSec();
285-
double second_absolute_position = initial_absolute_position + first_velocity * elapsed_time.toSec() + absolute_noise;
299+
double second_incremental_position = initial_incremental_position + velocity * elapsed_time.toSec();
300+
double second_absolute_position = initial_absolute_position + velocity * elapsed_time.toSec() + absolute_noise;
286301

287302
EXPECT_CALL(*this->imc, getIMCVoltage()).WillRepeatedly(Return(48));
288303
EXPECT_CALL(*this->imc, getAngleRadIncremental())
@@ -291,14 +306,15 @@ TEST_F(JointTest, TestReadEncodersNoUpdate)
291306
EXPECT_CALL(*this->imc, getAngleRadAbsolute())
292307
.WillOnce(Return(initial_absolute_position))
293308
.WillRepeatedly(Return(second_absolute_position));
309+
EXPECT_CALL(*this->imc, getVelocityRadIncremental()).WillRepeatedly(Return(velocity));
310+
EXPECT_CALL(*this->imc, getVelocityRadAbsolute()).WillRepeatedly(Return(velocity));
294311

295312
march::Joint joint("actuate_true", 0, true, std::move(this->imc));
296313
joint.prepareActuation();
297314

298315
joint.readEncoders(elapsed_time);
299316
joint.readEncoders(elapsed_time);
300317

301-
ASSERT_DOUBLE_EQ(joint.getPosition(), initial_absolute_position + 2 * first_velocity * elapsed_time.toSec());
302-
ASSERT_DOUBLE_EQ(joint.getVelocity(),
303-
(second_incremental_position - initial_incremental_position) / elapsed_time.toSec());
318+
ASSERT_DOUBLE_EQ(joint.getPosition(), initial_absolute_position + 2 * velocity * elapsed_time.toSec());
319+
ASSERT_DOUBLE_EQ(joint.getVelocity(), velocity);
304320
}

0 commit comments

Comments
 (0)