-
Notifications
You must be signed in to change notification settings - Fork 441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Output data via socket to an external server and wait for reply on an input socket #74
Comments
With an early test using this simplified server application, with the above No modifications of JSBSim code are required up to this point. I still have to sort out the blocking/non-blocking behaviour on the FGInputSocket side. |
Excellent ! Regarding the handshaking, I think we can take advantage of JSBSim initialization process to initialize the communication with the server. JSBSim initialization takes place in 2 phases: First phase
Second phase
SuspendIntegration();
Run();
Models[eInput]->InitModel();
Models[eOutput]->InitModel();
Run();
ResumeIntegration(); So even if the aircraft coordinates are not available to the server when data is polled from the input socket for the first time, the output socket will send the initial coordinates to the server at the end of this first Then the input and the output sockets are reset. This is mostly to hide that we have already processed a loop. For instance, the files are closed and re-opened thereby deleting (hiding) the output of the first initialization pass. Then Since all of this took place without time propagation, JSBSim is initialized at the end of the second So how this information is any relevant to the problem ?The idea is that when
My suggestion would then be to create a new class that inherits |
Possibly relevant to this discussion is a change I made for using JSBSim as a software-in-the-loop simulator for ArduPilot many years ago. The patch is here: |
Would you please post here a skeleton of the class you have in mind? |
This seems very similar to the already existing command However there is this method |
Sure, will do if you can wait till tomorrow (it's late now and I have to go 💤 😴 ) |
It blocks waiting for socket input using Which is why I mentioned to @WillemEerland that it looks very similar to @agodemar's suggestion for lock step simulation with an external process. |
After some investigations, the solution might not be as complicated as I initially described. My suggestion is to create a new method string FGfdmSocket::WaitForReply(void)
{
if (sckt > 0) {
char in_buf[4096]; // assume this is a sufficiently large buffer
int bytes_read = 0;
bytes_read = recv(sckt, in_buf, sizeof in_buf, 0); // MSG_PEEK -> check but does not read
data.append(in_buf, bytes_read);
}
return data;
} then @@ -119,7 +119,10 @@ void FGInputSocket::Read(bool Holding)
if (socket == 0) return;
if (!socket->GetConnectStatus()) return;
- data = socket->Receive(); // get socket transmission if present
+ if (waitForSocketReply)
+ data = socket->WaitForReply(); // block until a transmission is received
+ else
+ data = socket->Receive(); // get socket transmission if present
if (data.size() > 0) {
// parse lines This socket will block at the first iteration. Not sure, if this is a problem ?
AFAICT this is only applicable to |
Minor comment - let's not call the I'd suggest code along the following lines: void FGfdmSocket::WaitUntilReadable(void)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(sckt_in, &fds);
select(sckt_in+1, &fds, NULL, NULL, NULL);
} In other words use And then: @@ -119,7 +119,10 @@ void FGInputSocket::Read(bool Holding)
if (socket == 0) return;
if (!socket->GetConnectStatus()) return;
- data = socket->Receive(); // get socket transmission if present
+ if (blockingInput)
+ socket->WaitUntilReadable(); // block until a transmission is received
+ data = socket->Receive(); // read data
if (data.size() > 0) {
// parse lines |
I implemented some code in the PR #81 for this feature following the discussions we had above. |
Yes, fixed. I will close it. |
Here I collect the main points of a previous discussion in a closed PR #72 .
The idea
The idea comes from this research article demonstrating how JSBSim can be used to run flight simulations in presence of a gust field pre-calculated with OpenFOAM. This is what I do:
atmosphere/wind-north-fps
,atmosphere/wind-east-fps
, andatmosphere/wind-down-fps
.Configuration
The O/I can be configured via the
<output/>
and<input/>
tags as follows:Strategy
The server application (OpenFOAM server) should do most of the work. By design, the OpenFOAM server has to manage asynchronously several running instances of JSBSim (e.g. hundreds, or thousands) providing them the wind data according to aircraft positions in the flow field.
On the initial iteration of the sim loop the JSBSim input socket doesn't have an incoming connection yet, it's still waiting for a connection. So it doesn't block in this case it simply returns.
Then at the end of the first iteration of the sim loop the output socket sends the initial aircraft state to the OpenFOAM server. The OpenFOAM server on receiving this initial incoming connection now knows the IP address of JSBSim and so it then creates a connection to the input socket (with some configured port number, i.e. 1139) that is waiting for connections. And it sends back it's first set of wind velocities.
So now on the next iteration of the sim loop the input socket will be connected and it will issue a blocking read to retrieve the OpenFOAM set commands for the wind velocities etc. and will process them and return allowing the sim loop to now continue in lock-step with the OpenFOAM server.
Issue
Glancing at the socket code a bit it looks like currently for the input socket case the socket passed to the accept() API is set to non-blocking, so it won't block waiting for a connection. The socket passed to the recv() API is also set to non-blocking after a successful accept().
For the OpenFOAM case/example it is not critical that the very first sim loop iteration needs data from the OpenFOAM server.
There may be some cases where it is critical that JSBSim has to receive the input data from the external server on the very first simulation loop iteration. To handle that case we could potentially have multiple flags for the input socket which specify blocking versus non-blocking for the accept() and the recv() calls independently.
So for the OpenFOAM example one would leave the
accept()
as non-blocking but setrecv()
blocking. For another server where the initial data is critical one would set bothaccept()
andrecv()
to blocking. In which case JSBSim would start up but block until the external server connected and sent the first packet.The text was updated successfully, but these errors were encountered: