Changing attitude on user interaction

Hello everyone!

I am new to Orekit and want to achieve something quite simple. My situation is as follows:
I have a simulation with a satellite orbiting the Earth and its attitude is set to sun-pointing. The user of the simulation has the possibility to set another attitude mode for the satellite by interacting with it over a GUI. What I would like to achieve is that the user can set another attitude mode (e.g. nadir pointing) and the satellite transitions smoothly to the new attitude.
What I tried first is to have two AttitudeProviders running (CelestialBodyPointed for sun-pointing and NadirPointing for nadir pointing) and to use resetActiveProvider of the AttitudeSequence class. However, when I trigger the transition the satellite just does an instantaneous flip which is not the result I am looking for.
My next approach was to use addSwitchingCondition of the AttitudeSequence class. However, none of the already existing EventDetectors matched my condition (i.e. setting a flag from false to true), so I tried to implement a custom EventDetector. But now I am stuck there trying to implement the g method which has to be continuous around its roots because my condition is discrete.
Could you point me in a direction how I could tackle the g function or is there even another more elegant way to achieve what I need?

Cheers,
Yannick

Hi Yannick,

First of all, I suggest you to use the dev branch and then switch to the 10.0 official release once it will be out, because some bugs with AttitudeSequence have been corrected recently.

Your second approach is the correct way to use AttitudeSequence : initializing the two attitude provider in the AttitudeSequence, then adding some switching conditions. With this use, the Attitude Sequence will compute a smooth transition between the two states, over a transition time that you define.

You could imagine an additional state that contains the current attitude state (for instance 1 if nadir and -1 if sun pointing) and a g function that is a linear function going from the previous value (1 or -1) to the new attitude state (1 or -1) over a short time in case of attitude switch (This method will not be precise on the transition date).

Hope it can help you to use the AttitudeSequence class.
Romaric

Hello Romaric,

thank you for your reply! I will give your suggestion a try and let you know how it went :slight_smile:

Cheers,
Yannick

Okay, so I tried your idea and I think I am on a good way, but it still is not quite working. My detector looks as follows:

public class NadirDetector extends AbstractDetector<NadirDetector> {
    public static final double ATT_VALUE = 1;
    private boolean transitionStarted;
    private double transitionTime = 10000; // milliseconds
    private Instant startTime;

    public NadirDetector() {
      super(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, DEFAULT_MAX_ITER, null);
      transitionStarted = false;
    }

    @Override
    public void init(SpacecraftState s0, AbsoluteDate t) {
    }

    @Override
    public double g(SpacecraftState s) throws OrekitException {
      try {
        double att = s.getAdditionalState("attitude")[0];
        Instant now = Instant.now();
        double res = 0;
        if (att == ATT_VALUE && !transitionStarted) {
          startTime = now;
          transitionStarted = true;
          res = -1;
        } else if (att == ATT_VALUE && transitionStarted) {
          long ms = Duration.between(startTime, now).toMillis();
          res = 2.0 * ms / transitionTime - 1.0;
          if (ms >= transitionTime) {
            res = 1;
          }
        } else {
          transitionStarted = false;
          res = -1;
        }
        System.out.println("g = " + res);
        return res;
      } catch (OrekitException oe) {
        return -1;
      }
    }

    @Override
    public Action eventOccurred(SpacecraftState s, boolean increasing) throws OrekitException {
      System.out.println(
          "SWiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiITCH");
      return Action.CONTINUE;
    }

    @Override
    public SpacecraftState resetState(SpacecraftState oldState) throws OrekitException {
      transitionStarted = false;
      return oldState;
    }

    @Override
    protected NadirDetector create(double newMaxCheck, double newThreshold, int newMaxIter,
        EventHandler<? super NadirDetector> newHandler) {
      return new NadirDetector();
    }
  }

I noted the start time and started with a value of -1 and after 10000ms it should achieve a value of 1 by using a linear function.

I then implemented an AdditionalState provider which updates the currently set attitude inside the spacecraft state. The values show up when g is called, so I assume that worked.

I finally registered the EventDetector in the following way:

this.attitudesSequence = new AttitudesSequence();
NadirDetector nadirDetector = new NadirDetector();
attitudesSequence.addSwitchingCondition(sunPointing, nadirPointing, nadirDetector, true, true,
    10.0, null, null);
this.attitudesSequence.registerSwitchEvents(runningPropagator);
this.attitudeState = new AttitudeStateProvider(attitudeMode.getDoubleValue());
this.runningPropagator.addAdditionalStateProvider(attitudeState);

I update the attitudeStateProvider everytime before propagate is called.
Unfortunately, when I initialize the attitude change, I can see how my value of g transitions slowly from -1 to 1, but the eventOccured method is never called. Did I miss anything big? Are my time steps with milliseconds inside g too discrete?
Thanks,
Yannick