Modelling a simple satellite

115 views
Skip to first unread message

Jivan

unread,
Jun 22, 2016, 11:29:16 AM6/22/16
to europa-users
Hello!

I'm trying to use EUROPA to model a simple satellite that has a camera, battery and memory to store data. I have a few questions about issues I've had when trying to model this - I'm new to both planning and EUROPA so sorry if these are very simple questions! 

1. I have an action where data is being downlinked. Because the memory resource is set up with min/max levels specified, I didn't think it would be necessary to put a constraint within the action such that the data is only downlinked (consumed) when the memory level is > 0. However, it appears that the memory is able to go below the minimum level (0) specified in the initial state (as shown in the attached screenshot). I was wondering why this is possible when a min/max has been set? I've tried to add in another constraint in for this but wasn't sure how to refer to the current memory level (something like contained_by(object.nanosat.memory.ll_min > 0) ?). The action I have at the moment is below.

Transmitter::downlinkData
{
    after(object.nanosat.camera.takePhoto);
    contained_by(condition object.window.Available);
    contains(effect object.nanosat.memory.consume data);
    eq(data.quantity, duration);
}

2. It seems I can have the quantity of data downlinked/battery consumed to be equal to the duration of the action as above, however when I try to introduce a constant I get an error (e.g. eq(data.quantity, duration*12) - I've tried this in a few different ways such as initialising the constant in the action or in the camera or resource classes). It seems like this should be possible but is there a way I should be implementing it that I'm missing?

3. What would be the best way to go about generating a single example plan from EUROPA? At the moment, my model outputs a schedule which gives ranges for actions, e.g. the take photo action can start in the range [3,47]. I was wondering if there was a way to instead output a feasible plan that has each action at a specific time rather than a range? I'm using a similar table format to your Shopping example to visualise the schedule (shown in the screenshot).

I've also attached my model, initial state and bsh files as it might help to clarify where I'm going wrong.

I've had a look through the wiki and this group which are both really helpful - I don't think these questions have been asked before but apologies if I've missed something!

Thanks so much for your help!

Best,

Jivan
Nanosat1-model.nddl
Nanosat1.bsh
Nanosat1-initial-state.nddl
EUROPA_screenshot.tiff

Iatauro, Michael J. (ARC-TI)[QTS, INC]

unread,
Jun 22, 2016, 12:46:23 PM6/22/16
to europa...@googlegroups.com


June 22, 2016 at 4:12 AM
Hello!
Hello, Jivan!

I'm trying to use EUROPA to model a simple satellite that has a camera, battery and memory to store data. I have a few questions about issues I've had when trying to model this - I'm new to both planning and EUROPA so sorry if these are very simple questions!
Simple questions show us where we should improve our documentation, so they’re as much of a benefit to us as they are to you.

1. I have an action where data is being downlinked. Because the memory resource is set up with min/max levels specified, I didn't think it would be necessary to put a constraint within the action such that the data is only downlinked (consumed) when the memory level is > 0. However, it appears that the memory is able to go below the minimum level (0) specified in the initial state (as shown in the attached screenshot). I was wondering why this is possible when a min/max has been set? I've tried to add in another constraint in for this but wasn't sure how to refer to the current memory level (something like contained_by(object.nanosat.memory.ll_min > 0) ?). The action I have at the moment is below.

Transmitter::downlinkData
{
    after(object.nanosat.camera.takePhoto);
    contained_by(condition object.window.Available);
    contains(effect object.nanosat.memory.consume data);
    eq(data.quantity, duration);
}

The short version is that I think it’s because of the flexibility in the duration of Transmitter::downlinkData, the Solver not having any way to resolve the flaw, and printMemoryLevels only looking at the lower bound.

Resource profiles have an upper and lower bound that is guaranteed to envelop all possible grounded levels for the plan. That is, for every feasible assignment to all of the time and quantity variables, for all times t in the plan, lowerBound(t) <= level(t) <= upperBound(t). Min and max are constraints on those bounds. The plan contains a flaw if, at any point, lowerBound(t) < min or upperBound(t) > max. It contains a violation if lowerBound(t) > max or upperBound(t) < min.

I think what you’re seeing is a flaw, but because printMemoryLevels only prints the lower bound of the profile, it’s hard to tell. I think the flaw remains because everything that might resolve it has been filtered out of the Solver. The default Solver configuration filters out all temporal variables (start, end, duration, and time) as well as quantity variables on resources. Actually, I think it’s possible that flaws on all resources may be filtered out as well. Can you send that config file?

 
2. It seems I can have the quantity of data downlinked/battery consumed to be equal to the duration of the action as above, however when I try to introduce a constant I get an error (e.g. eq(data.quantity, duration*12) - I've tried this in a few different ways such as initialising the constant in the action or in the camera or resource classes). It seems like this should be possible but is there a way I should be implementing it that I'm missing?
Can you post the error message you’re getting? Is it a syntax error or some sort of runtime error? I think the problem might be in mixing the infix arithmetic syntax of with the textual eq. Try data.quantity = duration 12, or possibly mulEq(duration, 12, data.quantity).

3. What would be the best way to go about generating a single example plan from EUROPA? At the moment, my model outputs a schedule which gives ranges for actions, e.g. the take photo action can start in the range [3,47]. I was wondering if there was a way to instead output a feasible plan that has each action at a specific time rather than a range? I'm using a similar table format to your Shopping example to visualise the schedule (shown in the screenshot).

The Solver configuration file you've using probably filters all of the temporal variables out of the solution.  There'll be something that looks vaguely like this:

  <UnboundVariableManager defaultPriority="0">
    <FlawFilter var-match="start"/>
    <FlawFilter var-match="end"/>
    <FlawFilter var-match="duration"/>
  </UnboundVariableManager>

It looks like the durations in your model are mostly fixed, so if you just take out the filter on 'start' variables, you should get a grounded schedule.  The default is to go from min to max, so it'll be the optimistic, earliest-start schedule.  You may also want to ground the schedule /last/ so that it doesn't interfere with assembling the plan (this is one of those decisions that is highly domain- and model-dependent), so consider adding this:

  <FlawHandler var-match="start" component="StandardVariableHandler" priority="9999"/>

if you find that the Solver is wasting a bunch of time on early, bad decisions about start times.


I've also attached my model, initial state and bsh files as it might help to clarify where I'm going wrong.

I've had a look through the wiki and this group which are both really helpful - I don't think these questions have been asked before but apologies if I've missed something!
Please let us know where you think the wiki, in particular, could do better.  We accept commentary in the form of group posts and tickets.  

Thanks so much for your help!
Thanks so much for your interest!

--
-----------------------------------------
Michael J Iatauro
Software Engineer, IRIS Flight Controller
QTS, Inc.

NASA Ames Research Center
Office: 650-604-0662
Mail stop: 269-2
P.O. Box 1
Moffett Field, CA 94035-0001

Jivan

unread,
Jun 23, 2016, 10:48:31 AM6/23/16
to europa-users, michael....@nasa.gov
Hi Michael,

Thank you for getting back to me so quickly!

That makes sense - I didn't quite understand how the upper/lower bound stuff worked previously so thanks for explaining! Yes I think it is a flaw. I've updated my print statement to look at both the upper and lower bounds (screenshot attached) and it looks like at some points the lower bound < min (for the memory) and the upper bound > max (for the battery). I've attached the config file and it appears that there are filters on time and quantity there for the resources. I've tried removing these but it appears that for the battery at least the upper bound is still > max. 

Also, is there a way to look at just the resource level at a certain time point rather than the upper and lower bounds? I had a look through the PSResource classes but wasn't able to find anything.

For adding in the constant, using mulEq(duration, 12, data.quantity) worked, and I've changed the configuration as you suggested to get the grounded schedule.

Thanks again for all your help!

Jivan
EUROPA_screenshot_2.tiff
PlannerConfig.xml

Iatauro, Michael J. (ARC-TI)[QTS, INC]

unread,
Jun 23, 2016, 5:40:20 PM6/23/16
to europa-users


June 23, 2016 at 2:21 AM
Hi Michael,

Thank you for getting back to me so quickly!
Happy to help!


That makes sense - I didn't quite understand how the upper/lower bound stuff worked previously so thanks for explaining! Yes I think it is a flaw. I've updated my print statement to look at both the upper and lower bounds (screenshot attached) and it looks like at some points the lower bound < min (for the memory) and the upper bound > max (for the battery). I've attached the config file and it appears that there are filters on time and quantity there for the resources. I've tried removing these but it appears that for the battery at least the upper bound is still > max. 

Also, is there a way to look at just the resource level at a certain time point rather than the upper and lower bounds? I had a look through the PSResource classes but wasn't able to find anything.

The upper and lower bounds are the resource level.  If you're seeing different values for those bounds in your profile, then there's some flexibility in your plan, either in time or quantity.  Looking more closely at your model and Solver config, you've got a few different actions that use their duration to determine how much battery or data gets transacted.

Another one of those highly problem- and model-dependent choices is whether it's better to have the Solver decide the durations of those activities (which will propagate to the quantities) or decide the quantities (which will propagate back to the durations).  However, there are filters on duration and quantity that are preventing it from deciding either.

For adding in the constant, using mulEq(duration, 12, data.quantity) worked, and I've changed the configuration as you suggested to get the grounded schedule.
Did you try `data.quantity = duration * 12;`?  If it doesn't work, that's a bug.


Thanks again for all your help!
You're most welcome!

~MJI

Iatauro, Michael J. (ARC-TI)[QTS, INC]

unread,
Jul 5, 2016, 1:54:25 PM7/5/16
to europa-users
Jivan, I'm glad to see you're still sticking with Europa!  The short answer to your question is "no", but the short answer is a little wrong.  Before I get to that, though, is there a limitation to the existing resource model that's being problematic for you?

Europa core resource transactions are instantaneous, so their quantities have to be a constant*.  This lets (or forces, if you like) you to choose a discretization of the quantity if you want something more complicated than having the entire quantity transacted somewhere in the available time.  There's a fixed and a dynamic way to do this.

The fixed way is to pick a number of transactions and manually decompose it in the model:

Transmitter::downlinkData
{
    contains(effect object.nanosat.memory.consume data1);
    contains(effect object.nanosat.memory.consume data2);
    contains(effect object.nanosat.memory.consume data3);
    int quantity;
    mulEq(duration, 5, quantity);
    addEq(data1.quantity, data2.quantity, data3.quantity, quantity);
}

Which is slightly obnoxious to type and may not always suit, but keeps search relatively simple.

The dynamic option would be to add a loop, but the only thing that branches or loops is the Solver, so you're increasing search complexity:

Transmitter::downlinkData {
  int quantity;
  mulEq(duration, 5, quantity);
  starts(effect ConsumptionLooper.loop loop);
  loop.end <= end;
  loop.total = quantity; //the total amount to transact during the loop
  loop.max = 10; //the maximum amount to transact during each "iteration"
  loop.endTime = end; //make it easier to keep things in the right time horizon.
  loop.resource = object.nanosat.memory;

}

then

ConsumptionLooper::loop {
  contains(effect resource.consume c);
  c.quantity <= max;

  bool continueLoop;
  if(continueLoop) {
    meets(effect object.loop next);
    next.end <= endTime;
    next.max = max;
    next.endTime = endTime;
    addEq(next.quantity, max, c.quantity);
  }
}

This requires letting the Solver bind both the quantity of the consume transactions and the continueLoop boolean.  You also have to make sure that it's configured to search the quantity in descending order, or you risk ending up with single-unit consumptions and huge loops every time (which may be what you want).  Also, I didn't think hard enough to make sure the above doesn't contain bugs.

I suppose another possibility would be to add your own constraint that does the loop.

Paul Morris and John Bresina did some work on modeling piecewise-linear resource transactions with STN constraints and temporal flexibility (which it sounds like is really what you want) rather than piecewise-constant, but I don't think the source was ever opened and the algorithm was O(h^3), with h being the length of the horizon, if I remember correctly.

Another possibility would be to implement a closed-world, grounded resource with linear transactions, but that's not something doable in pure NDDL.  Like adding your own constraint that does the loop, you'd have to extend Europa at the C++ level.

~MJI
 

* Or at least can't be parameterized on the duration of the transaction.
July 5, 2016 at 7:20 AM
Hi again Michael! Hope you're well. I was wondering if there's a way to make an action continuous over a period of time? For example, I want to downlink data throughout the entire window that I've specified in my initial state or until the memory level reaches the lower limit of 0, whichever comes first. The way I have it at the moment (below), the action only occurs for one timestep even though I have a variable duration of [0,30]. Is it possible to do something like foreach(timestep in horizon) or while(memory > 0)? I'm not sure what the syntax for these types of statements would be in NDDL.

Thanks,

Jivan

class Transmitter
{
    Nanosatellite nanosat;
    Window window;
    
    Transmitter(Nanosatellite n)
    {
        nanosat = n;
        window = new Window();
    }
    
    action downlinkData{
        eq([0,30], duration);
    }
}

Transmitter::downlinkData
{
    after(object.nanosat.camera.takePhoto);
    contained_by(condition object.window.Available);
    contains(effect object.nanosat.memory.consume data);
    mulEq(duration, 5, data.quantity);
}

Iatauro, Michael J. (ARC-TI)[QTS, INC]

unread,
Jul 11, 2016, 12:53:26 PM7/11/16
to europa-users
The number five is suspicious =-).  Does the search always stop at five, or does it go past five and then backtrack?

~MJI

July 10, 2016 at 1:16 PM
Hi Michael,

Thank you for the explanations of all these options! :) I've implemented the resource transactions with the dynamic loops for now as you suggested, though I've structured them a bit differently to get it to work. 

I'm encountering some issues with the downlinking action that seems to be associated with adding in goals. For example, if I have one "takePhoto" goal the schedule output is as I would expect (the amount of loops I would expect to generate/consume the resources), but if I add a "measureRadiaton" goal or a second "takePhoto" goal starting at a different time, the amount of data downlinked always stops after 5 timesteps, even if the loop should be continuing (the time window is not over and there is still enough memory to allow additional downlink). Strangely this doesn't seem to be occurring for the battery resource though the power generation/consumption is structured similarly. Do you know why this might be? I'm not sure if I am specifying that the loop should continue in the right way. This is what I've added to the configuration file: <FlawHandler class="Transmitter" predicate="downlinkData" variable="continueLoop" component="Max"/> and the action is below.

Transmitter::downlinkData
{
    contained_by(condition object.window.Available);
    bool continueLoop;
    if(continueLoop) {
        meets(effect object.downlinkData next);
        next.end <= 90;
        starts(effect object.nanosat.memory.consume data);
        mulEq(duration, 5, data.quantity);
        
        starts(effect object.nanosat.mainBattery.consume consumption);
        mulEq(duration, 2, consumption.quantity);
    }
}

Thanks again,

Jivan
July 5, 2016 at 10:55 AM
Jivan, I'm glad to see you're still sticking with Europa!  The short answer to your question is "no", but the short answer is a little wrong.  Before I get to that, though, is there a limitation to the existing resource model that's being problematic for you?

Europa core resource transactions are instantaneous, so their quantities have to be a constant*.  This lets (or forces, if you like) you to choose a discretization of the quantity if you want something more complicated than having the entire quantity transacted somewhere in the available time.  There's a fixed and a dynamic way to do this.

The fixed way is to pick a number of transactions and manually decompose it in the model:

Transmitter::downlinkData
{
    contains(effect object.nanosat.memory.consume data1);
    contains(effect object.nanosat.memory.consume data2);
    contains(effect object.nanosat.memory.consume data3);
    int quantity;
    mulEq(duration, 5, quantity);
    addEq(data1.quantity, data2.quantity, data3.quantity, quantity);
 

June 23, 2016 at 2:41 PM


June 23, 2016 at 2:21 AM
Hi Michael,

Thank you for getting back to me so quickly!
Happy to help!

That makes sense - I didn't quite understand how the upper/lower bound stuff worked previously so thanks for explaining! Yes I think it is a flaw. I've updated my print statement to look at both the upper and lower bounds (screenshot attached) and it looks like at some points the lower bound < min (for the memory) and the upper bound > max (for the battery). I've attached the config file and it appears that there are filters on time and quantity there for the resources. I've tried removing these but it appears that for the battery at least the upper bound is still > max. 

Also, is there a way to look at just the resource level at a certain time point rather than the upper and lower bounds? I had a look through the PSResource classes but wasn't able to find anything.

The upper and lower bounds are the resource level.  If you're seeing different values for those bounds in your profile, then there's some flexibility in your plan, either in time or quantity.  Looking more closely at your model and Solver config, you've got a few different actions that use their duration to determine how much battery or data gets transacted.

Another one of those highly problem- and model-dependent choices is whether it's better to have the Solver decide the durations of those activities (which will propagate to the quantities) or decide the quantities (which will propagate back to the durations).  However, there are filters on duration and quantity that are preventing it from deciding either.
For adding in the constant, using mulEq(duration, 12, data.quantity) worked, and I've changed the configuration as you suggested to get the grounded schedule.
Did you try `data.quantity = duration * 12;`?  If it doesn't work, that's a bug.

Thanks again for all your help!
You're most welcome!

~MJI

June 23, 2016 at 2:21 AM
Hi Michael,

Thank you for getting back to me so quickly!

That makes sense - I didn't quite understand how the upper/lower bound stuff worked previously so thanks for explaining! Yes I think it is a flaw. I've updated my print statement to look at both the upper and lower bounds (screenshot attached) and it looks like at some points the lower bound < min (for the memory) and the upper bound > max (for the battery). I've attached the config file and it appears that there are filters on time and quantity there for the resources. I've tried removing these but it appears that for the battery at least the upper bound is still > max. 

Also, is there a way to look at just the resource level at a certain time point rather than the upper and lower bounds? I had a look through the PSResource classes but wasn't able to find anything.

For adding in the constant, using mulEq(duration, 12, data.quantity) worked, and I've changed the configuration as you suggested to get the grounded schedule.

Thanks again for all your help!

Jivan

--

Iatauro, Michael J. (ARC-TI)[QTS, INC]

unread,
Jul 12, 2016, 4:53:10 PM7/12/16
to europa-users
It looks like steps 65-70 have a roughly flat number of decisions in the plan, so it's doing some backtracking.  One might expect this behavior around these loops, as the Solver notices the end of the loop has been reached.  I'd try stepping through from about 55 to 75 to see what the Solver is deciding and why.

~MJI

July 11, 2016 at 11:57 AM
Sorry, I'm not 100% sure how to find this out! I find the solver stepping tool a bit confusing but looking at the solver open decisions, the open decision count seems to drop off after around time point 65 which is when the schedule ends unexpectedly (screenshot attached).

Thanks,

Jivan
July 11, 2016 at 9:55 AM

Iatauro, Michael J. (ARC-TI)[SGT, INC]

unread,
Jul 28, 2016, 1:42:13 PM7/28/16
to europa-users
Posting questions is what this group is for!

When you say "no plan appears to be generated", do you mean no plan at
all, or no complete plan? Is the Solver stopping because it's hit the
decision limit or because it's run out of things to decide?


~MJI


On 7/26/16 13:54, Jivan wrote:
> Sorry to post so many questions! Please disregard my last one - I
> think it might have been stuck in some sort of never ending loop, I've
> now constrained all my actions to be within a defined horizon and it
> doesn't seem to be happening anymore. Though now when I run for a
> larger number of steps (e.g. 1000) no plan appears to be generated,
> although there aren't any errors that come up... I think this could be
> because there are some inconsistencies arising as the search
> continues, will continue working on it!
>
> Thanks again for all your help with this!
>
> Jivan
Reply all
Reply to author
Forward
0 new messages