Hello, I faced the same problem. The reason is that the acceleration
calculation only takes into account the offset position (
m_offsetPose.GetPos()) without the orientation (m_offsetPose.GetRot()) (
chrono_sensor/sensors/ChIMUSensor.cpp
<https://github.com/projectchrono/chrono/blob/30cd3f2702cb58182e46d5b2724d2d2850a50e21/src/chrono_sensor/sensors/ChIMUSensor.cpp#L34-L39>
):
CH_SENSOR_API void ChAccelerometerSensor::PushKeyFrame() {
ChVector<double> tran_acc_no_offset =
m_parent->PointAccelerationLocalToParent(m_offsetPose.GetPos());
ChVector<double> tran_acc_offset = -m_parent->GetSystem()->Get_G_acc();
tran_acc_offset = m_parent->GetRot().Rotate(tran_acc_offset);
m_keyframes.push_back(tran_acc_no_offset + tran_acc_offset);
}
I made my own implementation of the accelerometer. I'm attaching it.
Maybe when I have time I'll make a pull request with these edits to the
main repository.
четверг, 19 декабря 2024 г. в 23:08:29 UTC+7, Yan Dong:
> Hi, I'm using Chrono 8.0.0, C++.
>
> I want to output accelerometer attached on a ChBody, but the acc output
> seems to be the acceleration on world frame not on the box frame. Also, I
> have find the acc output of gravity is strange.
>
> Here're my findings:
> 1. About the gravity: I set the gravity to be (0,0,-10), and I release the
> acc attached on a box to fall freely. The acc output is zero which is
> desired because no external force on box.
> Now I rotate the box, making the z-axis pointing downward, by:
>
> box->SetRot(Q_from_AngAxis(chrono::CH_C_PI, { 1, 0, 0 }));
>
> then the IMU output is now (0,0,-20). Which I think should be 0 becase the
> free falling has no external force. The real imu is 0 indeed.
>
>
> 2. About the extrinsics: I change the IMU attached extrinsics to the body,
> and I find the IMU output do not change at all no matter the what the
> extrinsics is:"
>
> auto ext_zero = chrono::ChFrame<double>({ 0, 0, 0 },
> Q_from_AngAxis(chrono::CH_C_PI, { 1, 0, 0 }));
> auto acc_ = chrono_types::make_shared<ChAccelerometerSensor>(box, 100,
> ext_zero, nullptr);
>
> 3. then I further find that the acc output seems to be the acceleration of
> the body in terms of the world frame but not its own frame. I add the an
> external world's X direction force and I find no matter the box is rotated
> (to negtive x direction) or the extrinsics is rotated, the Accelerometer
> output is always on x+ direction.
>
>
> So my questions are:
> a). How you implement Accelerometer calculation? What's the Accelerometer
> output's reference frame?
> b). How is the gravity effect on Accelerometer calculated? I guess is by
> relative moving frame together with the global gravity settings? But it's
> not true for a real Accelerometer.
>
>
> Here's my code. The 3 above findings are tested by codes with comments:
>
> ---------------------------------------------------
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> *ChSystemNSC sys; chrono::sensor::ChSensorManager manager_(&sys);
> sys.SetCollisionSystemType(ChCollisionSystem::Type::BULLET);
> sys.Set_G_acc({ 0, 0, -10 }); sys.SetSolverMaxIterations(20); auto
> ground_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>(); double
> friction_mu = 1.0; ground_mat->SetSfriction(friction_mu);
> ground_mat->SetKfriction(friction_mu); auto box =
> chrono_types::make_shared<ChBodyEasyBox>(1, 1, 1, 1.0, true, true,
> ground_mat); box->SetPos(ChVector<>(0, 0, 0.5)); // 1. Gravity Issue
> Rotate or Not. // box->SetRot(Q_from_AngAxis(chrono::CH_C_PI / 1, { 1,
> 0, 0 })); box->SetMass(1); box->SetInertiaXX(ChVector<>(1, 1, 1));
> box->SetBodyFixed(false); box->SetCollide(true); //
> sys.AddBody(box); // 2. Extrinsics Issue auto ext_zero =
> chrono::ChFrame<double>({ 0, 0, 0 }, Q_from_AngAxis(0, { 1, 0, 0 }));
> auto acc_ = chrono_types::make_shared<ChAccelerometerSensor>(box, 100,
> ext_zero, nullptr); acc_->SetName("IMU - Accelerometer");
> acc_->SetLag(0.0f); acc_->SetCollectionWindow(0.01);
> acc_->PushFilter(chrono_types::make_shared<ChFilterAccelAccess>());
> manager_.AddSensor(acc_); int imu_last_count_ = 0; // 3.
> Accelerometer direction issue by external force //
> std::shared_ptr<ChBody> ground; // create_ground(sys, ground);
> // I created a ground. // auto force1 =
> chrono_types::make_shared<ChForce>(); // box->AddForce(force1); //
> force1->SetMode(ChForce::FORCE); //
> force1->SetAlign(ChForce::WORLD_DIR); //
> force1->SetF_x(chrono_types::make_shared<ChFunction_Const>(20)); //
> force1->SetF_y(chrono_types::make_shared<ChFunction_Const>(0)); //
> force1->SetF_z(chrono_types::make_shared<ChFunction_Const>(0));
> while(1){ auto bufferAcc =
> acc_->GetMostRecentBuffer<UserAccelBufferPtr>(); if
> (bufferAcc->Buffer && bufferAcc->LaunchedCount > imu_last_count_) {
> AccelData acc_data = bufferAcc->Buffer[0];
> std::vector<double> acc(3); acc[0] = acc_data.X;
> acc[1] = acc_data.Y; acc[2] = acc_data.Z; cout <<
> acc[0] << ", " << acc[1] << ", " << acc[2] << endl;
> imu_last_count_ = bufferAcc->LaunchedCount; }
> manager_.Update(); sys.DoStepDynamics(0.001); }*
> ---------------------------------------------------
--
You received this message because you are subscribed to the Google Groups
"ProjectChrono" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/projectchrono/8aaa69a5-e48a-4742-8335-74981fdfd895n%40googlegroups.com.
#ifndef ACCELEROMETERSENSOR_HPP
#define ACCELEROMETERSENSOR_HPP
#include <vector>
#include "chrono/core/ChVector3.h"
#include "chrono_sensor/sensors/ChSensor.h"
#include "chrono_sensor/filters/ChFilter.h"
#include "chrono_sensor/sensors/ChNoiseModel.h"
using namespace chrono;
using namespace chrono::sensor;
class AccelerometerSensor : public ChDynamicSensor {
public:
/// Class constructor for an accelerometer sensor
/// @param parent Body to which the sensor is attached.
/// @param updateRate Rate at which the sensor should update.
/// @param offsetPose Relative position and orientation of the sensor with
respect to its parent object.
/// @param noise_model Noise model for the sensor to use when augmentating
data
AccelerometerSensor(std::shared_ptr<chrono::ChBody> parent,
float updateRate,
chrono::ChFrame<double> offsetPose,
std::shared_ptr<ChNoiseModel> noise_model)
: ChDynamicSensor(parent, updateRate, offsetPose) {
auto update_filter =
chrono_types::make_shared<FilterAccelerometerUpdate>(noise_model);
m_filters.push_front(std::static_pointer_cast<ChFilter>(update_filter));
}
/// Class destructor
~AccelerometerSensor() {}
virtual void PushKeyFrame() {
ChVector3d tran_acc_no_offset =
m_offsetPose.TransformDirectionParentToLocal(
m_parent->PointAccelerationLocalToParent(m_offsetPose.GetPos()));
ChVector3d g = m_offsetPose.TransformDirectionParentToLocal(
m_parent->TransformDirectionParentToLocal(m_parent->GetSystem()->GetGravitationalAcceleration()));
m_keyframes.push_back(tran_acc_no_offset + g);
}
virtual void ClearKeyFrames() { m_keyframes.clear(); }
private:
std::vector<ChVector3d> m_keyframes; ///< stores keyframes for sensor
friend class FilterAccelerometerUpdate;
};
/// Class for generating IMU data
class FilterAccelerometerUpdate : public ChFilter {
public:
/// Class constructor
/// @param noise_model The noise model to use when augmenting the IMU data
FilterAccelerometerUpdate(std::shared_ptr<ChNoiseModel> noise_model)
: m_noise_model(noise_model), ChFilter("Accelerometer Updater") {}
/// Apply function. Generates IMU data.
virtual void Apply() {
// default sensor values
ChVector3d acc = {0, 0, 0};
// get last measurements
if (m_accSensor->m_keyframes.size() > 0) {
// acc = m_accSensor->m_keyframes.back();
for (auto c : m_accSensor->m_keyframes) {
acc += c;
}
acc /= m_accSensor->m_keyframes.size();
}
if (m_noise_model) {
m_noise_model->AddNoise(acc);
}
// load IMU data
m_bufferOut->Buffer[0].X = acc.x();
m_bufferOut->Buffer[0].Y = acc.y();
m_bufferOut->Buffer[0].Z = acc.z();
m_bufferOut->LaunchedCount = m_accSensor->GetNumLaunches();
m_bufferOut->TimeStamp =
static_cast<float>(m_accSensor->GetParent()->GetSystem()->GetChTime());
}
/// Initializes all data needed by the filter access apply function.
/// @param pSensor A pointer to the sensor.
/// @param bufferInOut pointer to the process buffer
virtual void Initialize(std::shared_ptr<ChSensor> pSensor,
std::shared_ptr<SensorBuffer>& bufferInOut) {
if (bufferInOut) {
throw std::runtime_error("Accelerometer update filter must be
applied first in filter graph");
}
m_accSensor = std::dynamic_pointer_cast<AccelerometerSensor>(pSensor);
if (!m_accSensor) {
throw std::runtime_error("Accelerometer Update filter can only be
used on an accelerometer\n");
}
m_bufferOut = chrono_types::make_shared<SensorHostAccelBuffer>();
m_bufferOut->Buffer = std::make_unique<AccelData[]>(1);
m_bufferOut->Width = m_bufferOut->Height = 1;
m_bufferOut->LaunchedCount = m_accSensor->GetNumLaunches();
m_bufferOut->TimeStamp = 0.f;
bufferInOut = m_bufferOut;
}
private:
std::shared_ptr<AccelerometerSensor> m_accSensor;
std::shared_ptr<SensorHostAccelBuffer> m_bufferOut; ///< For holding
generated IMU data
std::shared_ptr<ChNoiseModel> m_noise_model; ///< The noise model
for augmenting data
};
#endif