child class 叶系统生成正弦信号
child class of leafsystem generating sinusoidal signal
我正在尝试制作 LeafSystem
的 child class,其输出是正弦曲线及其导数。
我编写了代码并尝试绘制它,但信号记录器没有正确记录。
#include "drake/systems/framework/leaf_system.h"
#include "drake/systems/analysis/simulator.h"
#include "drake/systems/framework/diagram.h"
#include "drake/systems/framework/diagram_builder.h"
#include "drake/systems/primitives/signal_logger.h"
#include "drake/common/proto/call_python.h"
class Sinusoid : public drake::systems::LeafSystem<double>
{
public:
Sinusoid (double tstart, double freq, double amp, double offset) :
m_freq(freq), m_amp(amp), m_offset(offset), m_tstart(tstart) {
this->DeclareVectorOutputPort(
drake::systems::BasicVector<double>(2), &Sinusoid::output);
}
private:
void output(const drake::systems::Context<double>& c, drake::systems::BasicVector<double>* output) const {
double t(c.get_time());
double tknot(t - m_tstart);
if (t > m_tstart) {
output->SetAtIndex(0, std::sin(tknot*m_freq + m_offset)*m_amp);
output->SetAtIndex(1, std::cos(tknot*m_freq + m_offset)*m_amp*m_freq);
} else {
output->SetAtIndex(0, 0.0);
output->SetAtIndex(1, 0.0);
}
}
double m_freq{0.0}, m_amp{0.0}, m_offset{0.0}, m_tstart{0.0};
};
int main(int argc, char *argv[])
{
// Add System and Connect
drake::systems::DiagramBuilder<double> builder;
auto system = builder.AddSystem<Sinusoid>(1.0, 2.*M_PI*1., 3., 0.);
auto logger = LogOutput(system->get_output_port(0), &builder);
auto diagram = builder.Build();
// Construct Simulator
drake::systems::Simulator<double> simulator(*diagram);
// Run simulation
simulator.StepTo(100);
// Plot with Python
auto sample_time = logger->sample_times();
auto sample_data = logger->data();
std::cout << sample_time.size() << std::endl;
for (int i = 0; i < sample_time.size(); ++i) {
std::cout << sample_time(i) << " : " << sample_data(i, 0) << " " << sample_data(i, 1) << std::endl;
}
std::cout << "END" << std::endl;
return 0;
}
代码的输出是
2
0 : 0 0
0 : 0 0
END
无论我在 StepTo
函数中使用的数字是多少,信号记录器只对采样时间均为 0 的 2 个数据进行分类。
代码看起来不错。请注意,TrajectorySource 几乎完全做到了这一点(并使用 SingleOutputVectorSource 作为基础 class,您也可以考虑这样做)。唯一的问题是您没有任何信息告诉模拟器有理由评估输出端口。记录器块将为每个发布事件使用它,但您还没有告诉模拟器发布。
解决方法是调用
simulator.set_publish_every_timestep(true)
如果你想进一步控制积分器的时间步长,你可以设置积分器的参数(例如simalator.get_integerator),然后调用set_fixed_step_mode。
我正在尝试制作 LeafSystem
的 child class,其输出是正弦曲线及其导数。
我编写了代码并尝试绘制它,但信号记录器没有正确记录。
#include "drake/systems/framework/leaf_system.h"
#include "drake/systems/analysis/simulator.h"
#include "drake/systems/framework/diagram.h"
#include "drake/systems/framework/diagram_builder.h"
#include "drake/systems/primitives/signal_logger.h"
#include "drake/common/proto/call_python.h"
class Sinusoid : public drake::systems::LeafSystem<double>
{
public:
Sinusoid (double tstart, double freq, double amp, double offset) :
m_freq(freq), m_amp(amp), m_offset(offset), m_tstart(tstart) {
this->DeclareVectorOutputPort(
drake::systems::BasicVector<double>(2), &Sinusoid::output);
}
private:
void output(const drake::systems::Context<double>& c, drake::systems::BasicVector<double>* output) const {
double t(c.get_time());
double tknot(t - m_tstart);
if (t > m_tstart) {
output->SetAtIndex(0, std::sin(tknot*m_freq + m_offset)*m_amp);
output->SetAtIndex(1, std::cos(tknot*m_freq + m_offset)*m_amp*m_freq);
} else {
output->SetAtIndex(0, 0.0);
output->SetAtIndex(1, 0.0);
}
}
double m_freq{0.0}, m_amp{0.0}, m_offset{0.0}, m_tstart{0.0};
};
int main(int argc, char *argv[])
{
// Add System and Connect
drake::systems::DiagramBuilder<double> builder;
auto system = builder.AddSystem<Sinusoid>(1.0, 2.*M_PI*1., 3., 0.);
auto logger = LogOutput(system->get_output_port(0), &builder);
auto diagram = builder.Build();
// Construct Simulator
drake::systems::Simulator<double> simulator(*diagram);
// Run simulation
simulator.StepTo(100);
// Plot with Python
auto sample_time = logger->sample_times();
auto sample_data = logger->data();
std::cout << sample_time.size() << std::endl;
for (int i = 0; i < sample_time.size(); ++i) {
std::cout << sample_time(i) << " : " << sample_data(i, 0) << " " << sample_data(i, 1) << std::endl;
}
std::cout << "END" << std::endl;
return 0;
}
代码的输出是
2
0 : 0 0
0 : 0 0
END
无论我在 StepTo
函数中使用的数字是多少,信号记录器只对采样时间均为 0 的 2 个数据进行分类。
代码看起来不错。请注意,TrajectorySource 几乎完全做到了这一点(并使用 SingleOutputVectorSource 作为基础 class,您也可以考虑这样做)。唯一的问题是您没有任何信息告诉模拟器有理由评估输出端口。记录器块将为每个发布事件使用它,但您还没有告诉模拟器发布。
解决方法是调用
simulator.set_publish_every_timestep(true)
如果你想进一步控制积分器的时间步长,你可以设置积分器的参数(例如simalator.get_integerator),然后调用set_fixed_step_mode。