"Scripter" avec Python et JPype - plaa/Modular GitHub Wiki

Table of Contents

"Scripter" dans openrocket avec Python et JPype

La possibilité d'écrire des scripts avec openrocket et de l'améliorer avec du code écrit par l'utilisateur et un sujet souvent abordé au sein de la communauté openrocket. Cet article montre une approche de cette problématique. Utiliser python http://python.org et la bibliothèque jPype http://jpype.sourceforge.net/ est possible pour écrire des scripts externes qui tournent en dehors d'openrocket, mais ils utilisent openrocket comme n'importe quelle autre bibliothèque python.

Cette approche met à disposition un environnement de développement très rapide pour optimiser des plans de fusées, améliorer et explorer les simulations. C'est également probablement la meilleure approche si vous êtes intéressés pour utiliser openrocket dans quelque chose de plus grand. Un avantage important avec cette approche par rapport à du script Jython intégré c'est que vous avez un accès complet à tout l'écosystème de python, d'une façon cruciale numpy http://numpy.scipy.org/, scipy http://scipy.org, matplotlib http://matplotlib.sourceforge.net et d'autres bibliothèques cpython. En revanche puisque les scripts ont besoins de logiciels externe ils ne peuvent pas être intégrés dans une distribution d'openrocket seule. Peux importe c'est une façon élégante de faire un prototype avec de nouvelles fonctionnalités pour openrocket.

Logiciels nécessaires

Pour lancer les exemples qui suivent vous aurez besoin de python 2.5 ou version plus récente de python 2.x, jpype, et un Openrocket .jar > 1.1.9. Les bibliothèques numpy, scipy, matplotlib sont nécessaires (elles sont en général distribuées ensemble). Tous ces scripts utilisent le module python orhelper.py (ci dessous).

Orhelper : orhelper.py

C'est un module relativement léger qui a été écrit pour ces exemples pour prendre en compte some of the more cumbersome aspects of scripting openrocket with jpype. A l'heure ou ces lignes sont écrites le modules orhelper contient:

  1. Une class OpenRocketInstance qui prend en charge le démarrage d'une JVM et d'une instance openrocket qui fonctionne. C'est équipé avec les fonctions ' et' et est sensé être appelé avec le constructeur 'with' http://effbot.org/zone/python-with-statement.htm de python 2.5. Ceci pour s'assurer que quoi qu'il arrive dans ce contexte la JVM se fermera toujours correctement et que vous aurez ( espérons le ) des informations utiles pour les exceptions.
  2. Une class Helper qui contient simplement un ensemble de fonctions helper utiles et un "wrapper" pour utiliser openrocket avec jpype. These are intended to take care of some of the more cumbersome aspects of calling methods, or provide more 'pythonic' data structures for general use. Le namespace net.sf.openrocket dans son integralité est disponible par la proprieté orp de cette class.
  3. Une classAbstractSimulationListener. Ceci est principalement une version python de la class openrocket.simulation.listerners du meme nom. Vous pouvez etendre cette class pour faire vos propre ecouteurs de simulation python et pour recevoir des "callbacks" de la simulation openrocket.
  4. Il y a egalement ici une petite class "wrapper", JIterator qui est pour utiliser des iterateurs java comme is ils etaient des iterateurs python.

Ceci est un exemple pour tracer le vol d'une fusée à l'aide de matplotlib. Un tracé de l'altitude et de la vitesse verticale en fonction du temps est généré, avec des annotations pour les divers événements un peu comme le tracé par défaut dans openrocket.

Dans cet exemple toutes les interactions avec openrocket sont faites au travers de divers méthodes d'Orhelper. La class orhelper.Helper sera à partir de maintenant nommée orh.

Tout d'abord nous démarrons une instance openrocket à l'intérieur de l'environnement protégé 'with'. Assurez vous de changer le nom du fichier .jar d'openrocket. Nous ouvrons ensuite un document openrocket, j'utilise ici le 'simple model rocket example'. Nous prenons ensuite un objet simulation dans ce fichier. Ce fichier a plusieurs simulations configurées, nous prendrons juste la première. Nous faisons ensuite tourner la simulation. Nous avons maintenant besoin d'extraire des données de la simulation. Ceci est réalisé à l'aide de la méthode orh.get_timeseries. Ceci retourne un dictionnaire de données timeseries (des tableaux numpy) from a simulation given a sequence of variable names. Les noms de variable sont fonction de la "locale" par défaut, regardez à l'interieur de la fenetre du tracé openrocket pour les noms exactes. Pour ajouter des anotations au tracé, nous avons besoin de prendre un dictionaire contenant tous les evenement de vol. Ceci est fait avec orh.get_events (les clefs sont les noms des événements et les valeurs sont les temps).

Le reste du code c'est des trucs matplotlib standard -- referez vous à leur documentation si vous n'etes pas familier. Certaines des fonctions inline méritent de plus ample explications. Je voulais avoir les labels des axes et les cases à cocher de la meme couleur que les lignes. Matplotlib ne peux pas changer toutes les cases à cocher de façon native, mais cela peut etre facilement fait avec la fonction change_color. Also, because get_events only gives us time information we need to extract the corresponding array index to put the annotations in the correct place. This done with the index_at function which in turn makes use of the numpy argmin function.

simple_plot.png

Exemple 2 : Fichier:lazy.py

Le but de cet exemple et de montrer comment une simulation peut être modifiée et de faire une démonstration de l'utilisation des fonctions numériques scipy. The toy problem we are attacking is the one of the rocketeer of maximum laziness who does not want to walk from the launch site to collect the rocket and would prefer if it flew exactly back of its own accord. We assume the rocket is flying upwind and optimise the launch rod angle accordingly. We want to plot a family of curves for a few different angles and highlight the optimised angle.

The structure of the program and initial lines for loading the model rocket are the same as in the previous example. In this example, we need to define a function for varying the launch angle before simulating the flight. This requires us to get the simulation options out of the simulation using the getOptions() method and we can then set the angle inside the SimulationOptions object. For the uninitiated, in openrocket simulation.SimulationOptions basically contains all the settings found in the simulation edit window. When the simulation is started these options are used to make a simulation.SimulationConditions object. After running the simulation we are interested in the 'Altitude' and 'Position upwind' variables. One option would be to just retrieve the final values with orh.get_final_values, however for reasons that will shortly become clear we have retrieved the whole time series.

For running an optimisation method, we need some function which is zero at the optimum point. This is not quite as simple as just getting the final upwind distance because the simulation stepper will usually slightly overshoot and calculate a final point with a negative altitude. We also want to exclude the launch. There are more elaborate ways this could be done --- here for simplicity we just slice out the last half of the data, find the index with the smallest absolute altitude and return the corresponding upwind distance. We can then go ahead and pass this to our optimisation method, giving some initial guess (40 deg) to start with. Scipy has a wide range of optimisation methods with a rich heritage, in our case we just choose the basic fmin which uses the downhill simplex algorithm.

In this example we want to plot a family of curves as well so we generate a range of 10 launch angles with np.linspace and add our optimal angle. We then run the simulations, making a list of all the timeseries data dictionaries and adding an 'Angle' key to each dictionary. We then go ahead and plot this, using a solid line style for the optimal curve and dashed lines for the others.

lazy.png

Exemple 3 : monte_carlo.py

As every student of introductory physics knows, presenting just a number as the result of a calculation is not really sufficient -- we also need to know the uncertainty to make it meaningful. The purpose of this example is to demonstrate a simple monte carlo method http://en.wikipedia.org/wiki/Monte_Carlo_method where multiple simulations are run with various parameters perturbed to determine an overall uncertainty for the landing location in terms of range and bearing from the launch site. This example also demonstrates the use of simulation listeners implemented in python. Openrocket simulation listeners are covered in section 9 of the users guide.

La structure de ce script est légerement differente des exemples precedents. First consider how we get the landing range and bearing information. This information is not available directly as a simulation variable, although latitude and longnitude are. One option would be to get these variables and do the calculation in python. However, openrocket already includes methods to do this as part of util.GeodeticComputationStratery which is a parameter of each simulation, so it is nice to make use of these which operate natively on util.WorldCoordinate objects. We do this by defining a new simulation listener LandingPoint which extends orhelper.AbstractSimulationListener. We define an endSimulation method which grabs the simulation GeodeticComputationStratergy and uses it to find the range and bearing from the lanuch site WorldCoordinate (from SimulationConditions) to the rocket position (from SimulationStatus). These are saved as LandingPoint instance variables.

Multiple LandingPoint objects are stored in a LandingPointList, which is like a regular list except can populate itself with landing points by running multiple openrocket simulations. Various parameters are set by choosing from a gaussian distribution with given mean and standard deviation (pythons random.gauss method). The code for running the simulations has mostly been discussed earlier, and the same example rocket is used although in my case I turned up the wind and turbulance somewhat and switched to a spherical earth computation method. One aspect that is new is the modification of the rocket model. A rocketcomponent.Rocket object can be obtained from the simulation options. This is the root of a tree type data structure containing all the rocket components. Our orh.Helper class has a method for finding components in the tree given their names. We use this to obtain the nose cone and body tube components and override their masses with perturbed values. Running the simulation is again done using orh.runsimulation, except in this case we pass in a sequence of listener objects to use. To increase the variability still we pass in a AirStart listener with randomly set start altitude. This listener is a python copy of the example supplied with openrocket.

Finally, when run the main function of the script makes a new LandingPointList, populates it and then uses the print_stats method to show the final landing statistics, something like:

Zone d'atterissage de la fusée 3833.57 m +- 1116.91 m bearing -89.98 deg +- 0.0713 deg depuis le site de lancement. Basé sur 20 simulations.

Notez que cela prendra sans doute une minute ou deux pour faire tourner toutes ces simulations.

⚠️ **GitHub.com Fallback** ⚠️