WPILib ile Fizik Simülasyonu
Çünkü durum-uzay gösterimi , :systems ‘in dynamics kompakt bir şekilde temsil etmemize olanak tanır, robotlarda fiziksel sistemleri simüle etmek için onu kullanabiliriz. Bu simülatörlerin amacı, mevcut simülasyon dışı kullanıcı kodunu değiştirmeden robot mekanizmalarının hareketini simüle etmektir. Bu tür simülatörlerin temel akışı aşağıdaki gibidir:
Normal kullanıcı kodunda:
PID veya benzer kontrol algoritmaları, kodlayıcı (veya diğer sensör) okumalarından voltaj komutları üretir
Motor çıkışları ayarlandı
Simülasyon periyodik kodunda:
Simülasyonun state`i, :term:`inputs genellikle bir PID döngüsünden ayarlanmış motorlardan gelen voltajlar kullanılarak güncellenir.
Simüle edilmiş kodlayıcı (veya diğer sensör) okumaları, sonraki zaman adımında kullanıcı kodunun kullanılması için ayarlanır
WPILib’in Simülasyon Sınıfları
WPILib’de aşağıdaki fizik simülasyon sınıfları mevcuttur:
Doğrusal dinamikli sistemleri modellemek için LinearSystemSim,
FlywheelSim - Volan Sim
DiferansiyelDrivetrainSim
ElevatorSim, which models gravity in the direction of elevator motion
SingleJointedArmSim, which models gravity proportional to the arm angle
Akü voltajı düşüşünü çekilen akımlara göre tahmin eden BatterySim
Tüm simülasyon sınıfları (diferansiyel sürücü simülatörü haricinde) LinearSystemSim
sınıfından miras alır. Varsayılan olarak, dinamikler doğrusal sistem dinamikleridir \(\mathbf{x}_{k+1} = \mathbf{A}\mathbf{x}_k + \mathbf{B}\mathbf{u}_k\) . Alt sınıflar UpdateX(x, u, dt)
gibi methorları, yerçekimi modelleme, özel ve doğrusal olmayan dinamikler sağlamak için yöntemini geçersiz kılar.
Not
Swerve support for simulation is in the works, but we cannot provide an ETA. For updates on progress, please follow this pull request.
Kullanıcı Kodunda Kullanım
Aşağıdakiler WPILib’den edinilebilir elevatorsimulation
example project.
In addition to standard objects such as motors and encoders, we instantiate our elevator simulator using known constants such as carriage mass and gearing reduction. We also instantiate an EncoderSim
, which sets the distance and rate read by our Encoder
.
Aşağıdaki örnekte, hareketli taşıyıcının kütlesi (kilogram cinsinden), asansörü tahrik eden tamburun yarıçapı (metre cinsinden), giriş üzerinden çıkış olarak motor ve tambur arasındaki dişli azalması (genellikle birden daha büyüktür) ile verilen bir asansörü simüle ediyoruz, asansörün minimum ve maksimum yüksekliği (metre cinsinden) ve konum tahminimize eklenecek bazı rastgele gürültü.
Not
Asansör ve kol simülatörleri, simüle edilmiş konumun verilen minimum veya maksimum yükseklik veya açıları aşmasını önleyecektir. Sonsuz dönme veya harekete sahip bir mekanizmayı simüle etmek istiyorsanız, LinearSystemSim
daha iyi bir seçenek olabilir.
47 // Simulation classes help us simulate what's going on, including gravity.
48 private final ElevatorSim m_elevatorSim =
49 new ElevatorSim(
50 m_elevatorGearbox,
51 Constants.kElevatorGearing,
52 Constants.kCarriageMass,
53 Constants.kElevatorDrumRadius,
54 Constants.kMinElevatorHeightMeters,
55 Constants.kMaxElevatorHeightMeters,
56 true,
57 VecBuilder.fill(0.01));
58 private final EncoderSim m_encoderSim = new EncoderSim(m_encoder);
51 // Simulation classes help us simulate what's going on, including gravity.
52 frc::sim::ElevatorSim m_elevatorSim{m_elevatorGearbox,
53 Constants::kElevatorGearing,
54 Constants::kCarriageMass,
55 Constants::kElevatorDrumRadius,
56 Constants::kMinElevatorHeight,
57 Constants::kMaxElevatorHeight,
58 true,
59 {0.01}};
60 frc::sim::EncoderSim m_encoderSim{m_encoder};
Daha sonra, teleopPeriodic
/TeleopPeriodic
(Java/C++), asansörümüzü yerden 30 inç yükseklikte bir ayar noktasına götürmek için basit bir PID kontrol döngüsü kullanır.
31 @Override
32 public void teleopPeriodic() {
33 if (m_joystick.getTrigger()) {
34 // Here, we set the constant setpoint of 0.75 meters.
35 m_elevator.reachGoal(Constants.kSetpointMeters);
36 } else {
37 // Otherwise, we update the setpoint to 0.
38 m_elevator.reachGoal(0.0);
39 }
40 }
98 public void reachGoal(double goal) {
99 m_controller.setGoal(goal);
100
101 // With the setpoint value we run PID control like normal
102 double pidOutput = m_controller.calculate(m_encoder.getDistance());
103 double feedforwardOutput = m_feedforward.calculate(m_controller.getSetpoint().velocity);
104 m_motor.setVoltage(pidOutput + feedforwardOutput);
105 }
20void Robot::TeleopPeriodic() {
21 if (m_joystick.GetTrigger()) {
22 // Here, we set the constant setpoint of 0.75 meters.
23 m_elevator.ReachGoal(Constants::kSetpoint);
24 } else {
25 // Otherwise, we update the setpoint to 0.
26 m_elevator.ReachGoal(0.0_m);
27 }
28}
42void Elevator::ReachGoal(units::meter_t goal) {
43 m_controller.SetGoal(goal);
44 // With the setpoint value we run PID control like normal
45 double pidOutput =
46 m_controller.Calculate(units::meter_t{m_encoder.GetDistance()});
47 units::volt_t feedforwardOutput =
48 m_feedforward.Calculate(m_controller.GetSetpoint().velocity);
49 m_motor.SetVoltage(units::volt_t{pidOutput} + feedforwardOutput);
50}
Daha sonra, simulationPeriodic
/SimulationPeriodic
(Java/C++), asansörün simüle edilmiş konumunu güncellemek için motora uygulanan gerilimi kullanır. Sadece simüle edilmiş robotlar için periyodik olarak çalıştığı için SimulationPeriodic
kullanıyoruz. Bu, simülasyon kodumuzun gerçek bir robot üzerinde çalıştırılmayacağı anlamına gelir.
Not
Classes inheriting from command-based’s Subsystem
can override the inherited simulationPeriodic()
method. Other classes will need their simulation update methods called from Robot
’s simulationPeriodic
.
Son olarak, simüle edilmiş kodlayıcının mesafe okuması, simüle edilmiş asansörün konumu kullanılarak ayarlanır ve robotun pil voltajı, asansör tarafından çekilen tahmini akımı kullanılarak ayarlanır.
78 public void simulationPeriodic() {
79 // In this method, we update our simulation of what our elevator is doing
80 // First, we set our "inputs" (voltages)
81 m_elevatorSim.setInput(m_motorSim.getSpeed() * RobotController.getBatteryVoltage());
82
83 // Next, we update it. The standard loop time is 20ms.
84 m_elevatorSim.update(0.020);
85
86 // Finally, we set our simulated encoder's readings and simulated battery voltage
87 m_encoderSim.setDistance(m_elevatorSim.getPositionMeters());
88 // SimBattery estimates loaded battery voltages
89 RoboRioSim.setVInVoltage(
90 BatterySim.calculateDefaultBatteryLoadedVoltage(m_elevatorSim.getCurrentDrawAmps()));
91 }
20void Elevator::SimulationPeriodic() {
21 // In this method, we update our simulation of what our elevator is doing
22 // First, we set our "inputs" (voltages)
23 m_elevatorSim.SetInput(frc::Vectord<1>{
24 m_motorSim.GetSpeed() * frc::RobotController::GetInputVoltage()});
25
26 // Next, we update it. The standard loop time is 20ms.
27 m_elevatorSim.Update(20_ms);
28
29 // Finally, we set our simulated encoder's readings and simulated battery
30 // voltage
31 m_encoderSim.SetDistance(m_elevatorSim.GetPosition().value());
32 // SimBattery estimates loaded battery voltages
33 frc::sim::RoboRioSim::SetVInVoltage(
34 frc::sim::BatterySim::Calculate({m_elevatorSim.GetCurrentDraw()}));
35}