GEO station keeping handler

Hello! I am using the LongitudeCrossingDetector and LatitudeCrossingDetector to determine when an impulsive maneuver needs to be done for a GEO. This is working perfectly.

I set up a handler to perform a maneuver when the event occurs. Within this handler, another detector is needed to figure out when the GEO is at apogee/perigee or crossing the line of apsides. I only want this event detector working after latitude/longitude crossing was detected, but I am unsure how to do that.

Any help would be greatly appreciated!

You can use an EventEnablingPredicateFilter that will wrap the second detector and trigger it only based on an EnablingPredicate you will provide. This enabling predicate will simply have to hold a boolean that will be switched when the first event occurs.

Thank you for the suggestion @luc

So, I have used the EventEnablingPredicateFilter to wrap around the second detector with an EnablingPredicate that is set to currentState.getDate().isBefore(lastAllowedDate).

I then use this EventEnablingPredicateFilter to trigger the maneuver as follows:

maneuver = ImpulseManeuver(trigger_perigee, attitudeProvider, delta_v, 220.0)
maneuver = maneuver.of_(ApsideDetector)

This is all inside the eventOccurred method of the PythonEventHandler class I created. However, when I attempt to propagate the GEOs using the TLEPropagator I keep getting the following error message:

JavaError: <super: <class 'JavaError'>, <JavaError object>>
Java stacktrace:
java.lang.RuntimeException: NameError
at org.orekit.python.PythonEventHandler.eventOccurred(Native Method)
at org.orekit.propagation.analytical.AbstractAnalyticalPropagator.acceptStep(
at org.orekit.propagation.analytical.AbstractAnalyticalPropagator.propagate(
at org.orekit.propagation.AbstractPropagator.propagate(
at org.orekit.propagation.AbstractPropagator.getPVCoordinates(


Seems like something is going wrong in the python event handler method eventOccured - name error. If I understand you right, the exact same eventOccured method is working in another propagator?

Do you have a expected-to-work-but-don’t code to share, it is easier to spot then?


Hi @petrus.hyvonen! I have not gotten it to work yet with any propagator, I was trying to test it with the TLEPropagator as it is much faster. However, I am currently running it with the numerical propagator, but still waiting for that to finish. Here is my simplified version of the handler:

class LatitudeCrossingHandler(PythonEventHandler):

    def init(self, initialstate, target):

    def eventOccurred(self, s, T, increasing):  # impulsive inclination maneuver
        inertialFrame = FramesFactory.getEME2000()

        # need to ensure the Z axis is aligned with orbital momentum,
        # so we select an attitude aligned with LVLH Local Orbital frame
        attitudeProvider = LofOffset(inertialFrame, LOFType.LVLH)

        ascendingNodeStopper = NodeDetector(300.0, 1e-6, 100, StopOnIncreasing()) # check later, 100 madeup

        lastAllowedDate = currentState.getDate().shiftedBy(1.0 * currentState.getKeplerianPeriod()) # let maneuvers happen for 1 orbits
        predicate = currentState.getDate().isBefore(lastAllowedDate)
        trigger = EventEnablingPredicateFilter(ascendingNodeStopper, predicate)

        delta_v = Vector3D(SomeArray)  # calculate required impulsive velocity change

        maneuver = ImpulseManeuver(trigger, attitudeProvider, delta_v, 220.0)
        maneuver = maneuver.of_(NodeDetector)


        return Action.CONTINUE

    def resetState(self, detector, oldState):
        """Reset TimingEvent handler to given state."""
        return oldState




It is really hard to see without running it. One way to debug (if you are not using a debugger) is to do the return statement at different locations in the eventOccured method and try to figure out which line is giving the error. That’s narrows down the problem a bit.

Currently I am struggling to get the EventEnablingPredicateFilter working. It requires an EnablingPredicate but I keep getting a NotImplementedError when I try to create an instance.

I would like to have it so it only performs the ImpulseManeuver for the next couple perigee passes, where I define the predicate as:

lastAllowedDate = s.getDate().shiftedBy(3 * s.getKeplerianPeriod()) # let maneuvers happen for 3 orbits
predicate = s.getDate().isBefore(lastAllowedDate)