djungelorm

[1.4.x,1.3.x,1.2.2] kRPC: Remote Procedure Call Server (v0.4.7, 27th July 2018)

Recommended Posts

Is there any way to use this with C or will I have to integrate with Python?

In principle this should be straightforward - you just need a sockets library and the protocol buffers library. Then its just a matter of building the message to send over TCP to the server and wait for a reply, or am I missing something?

edit: by "this" I assumed you meant the krpc addon in general (not the krpc-toolkit).

Share this post


Link to post
Share on other sites

Apologies for the late response, work has been getting in the way lately... but thanks for the help! Your response resolved my issue and makes sense! Also appreciate all the time and effort you have put into this MOD, really opens the door to do some really cool stuff in KSP. Plus it's a fun platform to learn python and a good use for my raspberry pi.

I'm currently working on a Mun landing script and one of the critical data streams is the ships vertical speed. The following code is attempting to setup a stream to access my vertical speed and is based off the syntax used to setup the altitude (which is also from the flight class). Unfortunately the current setup always returns 0 for my vertical speed. I belive i am making the correct class call but not sure why it's always zero...


Vertical_Speed = conn.add_stream(getattr, vessel.flight(), 'vertical_speed')

print ('\nVertical Speed = %d' % Vertical_Speed())

Thanks,

Share this post


Link to post
Share on other sites
Apologies for the late response, work has been getting in the way lately... but thanks for the help! Your response resolved my issue and makes sense! Also appreciate all the time and effort you have put into this MOD, really opens the door to do some really cool stuff in KSP. Plus it's a fun platform to learn python and a good use for my raspberry pi.

I'm currently working on a Mun landing script and one of the critical data streams is the ships vertical speed. The following code is attempting to setup a stream to access my vertical speed and is based off the syntax used to setup the altitude (which is also from the flight class). Unfortunately the current setup always returns 0 for my vertical speed. I belive i am making the correct class call but not sure why it's always zero...


Vertical_Speed = conn.add_stream(getattr, vessel.flight(), 'vertical_speed')

print ('\nVertical Speed = %d' % Vertical_Speed())

Thanks,

Sorry for the slow response! It returns zero because the reference frame you are using moves with the vessel (by default vessel.flight() uses reference frame vessel.reference_frame). What you want is a reference frame that is fixed relative to the surface under the vessel, i.e. vessel.orbit.body.reference_frame

The following should do what you want:


ref = vessel.orbit.body.reference_frame
Vertical_Speed = conn.add_stream(getattr, vessel.flight(ref), 'vertical_speed')

print ('\nVertical Speed = %d' % Vertical_Speed())

Edited by djungelorm

Share this post


Link to post
Share on other sites

I was trying to write an auto-launch script for the Saturn V in RSS/RO with kOS, but the steering autopilot did not work since the rocket receives its control through engine gimbals instead of reaction wheels (see this post on the kOS forums). I re-wrote the launch script as a python script for kRPC and I was having the same issue. I saw that kRPC borrows from other mods such as kOS for the autopilot coding, so it seems kRPC has the same problem as kOS regarding steering control for rockets that do not use reaction wheels primarily for control.

Share this post


Link to post
Share on other sites
I was trying to write an auto-launch script for the Saturn V in RSS/RO with kOS, but the steering autopilot did not work since the rocket receives its control through engine gimbals instead of reaction wheels (see this post on the kOS forums). I re-wrote the launch script as a python script for kRPC and I was having the same issue. I saw that kRPC borrows from other mods such as kOS for the autopilot coding, so it seems kRPC has the same problem as kOS regarding steering control for rockets that do not use reaction wheels primarily for control.

I'm actually in the process of rewriting the autopilot code to use a PID controller (details here https://github.com/djungelorm/krpc/issues/75), and will be included in the next release. Should hopefully resolve this issue, but thanks for bringing this to my attention. The current autopilot was indeed adapted from kOS/MechJeb/etc.

Share this post


Link to post
Share on other sites

Awesome! I look forward to it. Keep up the good work! I try to use kOS because it's more "Kerbalish", but I end up going back to kRPC: I prefer to use a language that I actually know well (and is complete), plus I'm not restricted to just in-game resources and can use external libraries like any real program.

Share this post


Link to post
Share on other sites

Is there a way to send commands to my vessel using kRPC when I lose (RemoteTech) connection?. I am trying to use kRPC as an "on-board" computer to put my satellite network in orbit but when I lose connection my program stops executing. For my particular case, when I don't have a connection I would like to be able to execute (kRPC) programs but still be unable to control my vessel from the keyboard. Is there some simple way to achieve this?

BTW, great mod. I'm trying to make my own kRPC client using my own favorite language: Common Lisp :sticktongue:

Share this post


Link to post
Share on other sites
Is there a way to send commands to my vessel using kRPC when I lose (RemoteTech) connection?. I am trying to use kRPC as an "on-board" computer to put my satellite network in orbit but when I lose connection my program stops executing. For my particular case, when I don't have a connection I would like to be able to execute (kRPC) programs but still be unable to control my vessel from the keyboard. Is there some simple way to achieve this?

BTW, great mod. I'm trying to make my own kRPC client using my own favorite language: Common Lisp :sticktongue:

Ooops... looks like I broke the RemoteTech integration slightly in 0.1.10. The intended behaviour is indeed for your scripts to still work if the connection is lost -- and if you want your script to stop working you can always check vessel.comms.has_connection. I'll fix this and a get a new release out soon as I can!

Share this post


Link to post
Share on other sites
Ooops... looks like I broke the RemoteTech integration slightly in 0.1.10. The intended behaviour is indeed for your scripts to still work if the connection is lost -- and if you want your script to stop working you can always check vessel.comms.has_connection. I'll fix this and a get a new release out soon as I can!

Upon further testing... everything seems to work fine when I don't have connection except the throttle. I don't know, maybe it's a conflict with another of my mods. I will try to test it with just kRPC + RemoteTech

Share this post


Link to post
Share on other sites
Upon further testing... everything seems to work fine when I don't have connection except the throttle. I don't know, maybe it's a conflict with another of my mods. I will try to test it with just kRPC + RemoteTech

Yeah I'm seeing that throttle behaviour too with just kRPC and RemoteTech. It looks like setting the throttle using FlightInputHandler.state.mainThrottle is disabled by RemoteTech.

I also found another issue with control inputs: getting the values of the roll/pitch/yaw inputs doesn't return what's shown on the HUD. It just returns what was set using kRPC.

Share this post


Link to post
Share on other sites

I'm trying to get surface velocity vector. I can not find any direct way to get it. Best I managed was


refframe = vessel.orbit.body.reference_frame
surface_ref = vessel.surface_reference_frame
v_vector = conn.space_center.transform_direction(vessel.velocity(refframe),refframe,surface_ref)

But this method is really inaccurate around around ground altitude, probably due to rounding.

Is there better way?

Share this post


Link to post
Share on other sites

I think that is the most direct way. I tried it out the following code for a plane flying low around KSC, and it returns an accurate vector. What situation is causing you to get poor results?


import krpc
import time
import sys
import numpy as np

conn = krpc.connect()
vessel = conn.space_center.active_vessel

while True:

refframe = vessel.orbit.body.reference_frame
surface_ref = vessel.surface_reference_frame
v_vector = conn.space_center.transform_direction(vessel.velocity(refframe),refframe,surface_ref)

conn.space_center.clear_drawing()
conn.space_center.draw_line((0,0,0), v_vector, surface_ref, (1,0,0))

print '(%+.4f, %+.4f, %+.4f)' % v_vector, '%+.4f' % np.linalg.norm(v_vector)
time.sleep(0.1)

Results:


(+52.1619, +181.1078, +142.7503) +236.4287
(+52.1747, +181.1405, +142.7724) +236.4699
(+52.1794, +181.1772, +142.7983) +236.5148
(+52.1910, +181.2066, +142.8070) +236.5451
(+52.2081, +181.2417, +142.8388) +236.5949
...

- - - Updated - - -

Version 0.1.11 has been released!

Download link: https://kerbalstuff.com/mod/636/kRPC...0Call%20Server

The main changes are:

  • Added a Lua client
  • Rewritten the autpilot to use a PID controller, which can be manually tuned
  • The active vessel is settable (you can use this to switch vessels)
  • Added functions to launch new vessels from the VAB/SPH
  • Added more thermal properties from the improved heating model in KSP 1.0.4
  • Support for FAR 0.15
  • Fix bug setting the throttle with RemoteTech enabled and no connection

Enjoy!

Share this post


Link to post
Share on other sites

I've been fiddling with using kRPC recently, trying to use it from a C# program. I've hit a bit of a brick wall with property getters and setters.

For example, the GetServices call tells me this:


Vessel_set_Name
Class.Property.Set(SpaceCenter.Vessel,Name)
ParameterType(0).Class(SpaceCenter.Vessel)

So according to this, setting the name doesn't take a name parameter. This seems to be a problem with all property setters, including rather important ones like set throttle!

Where do I pass in the parameter to set this property to?

Just for reference, here's my current test code:


//KRPC.cs
internal byte[] RawRequest(string name, string service, params Argument[] args)
{
Request r = new Request
{
Procedure = name,
Service = service,
Arguments = args
};

Serializer.SerializeWithLengthPrefix(_rpcStream, r, PrefixStyle.Base128);

var response = Serializer.DeserializeWithLengthPrefix<Response>(_rpcStream, PrefixStyle.Base128);

if (response.Error != null)
throw new RpcException(response.Error);

return response.ReturnValue;
}

//Vessel.cs
public string Name
{
set
{
Rpc.RawRequest("Vessel_set_Name", "SpaceCenter", Argument.Create(0, this)); // <-- Encoding "this" as an argument simply passes back exactly whatever byte array was received from the server when this proxy object was created
}
}

Version 0.1.11 has been released!

It looks like this version hasn't made it onto CKAN yet :(

Share this post


Link to post
Share on other sites

Where do I pass in the parameter to set this property to?

Vessel_set_Name takes two parameters, the first is of type int (and is the id of the remote object) and the second is of type string (the name). So you probably want something like:


public string Name {
set {
Rpc.RawRequest("Vessel_set_Name", "SpaceCenter", Argument.Create(0, this), Argument.Create(1, value));
}
}

GetServices should return the following information for Vessel_set_Name (the following is output by a python script I use to generate the documentation). This shows the two parameters, and the attributes that indicates that although the first parameter is an int, it's actually a reference to an object (rather than just being a number). There is no attribute for the string parameter as it's simply a string.


"Vessel_set_Name": {
"parameters": [
{
"default_argument": null,
"name": "this",
"type": "uint64"
},
{
"default_argument": null,
"name": "value",
"type": "string"
}
],
"return_type": "",
"attributes": [
"Class.Property.Set(SpaceCenter.Vessel,Name)",
"ParameterType(0).Class(SpaceCenter.Vessel)"
]
},

It looks like this version hasn't made it onto CKAN yet :(

It's up on KerbalStuff so is probably just taking some time to update.

Share this post


Link to post
Share on other sites

GetServices should return the following information for Vessel_set_Name...

Aha - I was looking at the attributes, not the parameters. Oops!

you probably want something like:


public string Name {
set {
Rpc.RawRequest("Vessel_set_Name", "SpaceCenter", Argument.Create(0, this), Argument.Create(1, value));
}
}

A reasonable guess, but it doesn't quite encode things correctly. Could you point me to the place within the server that encodes/decodes these values, I'll tear out that code and reuse it myself :)

Share this post


Link to post
Share on other sites
A reasonable guess, but it doesn't quite encode things correctly. Could you point me to the place within the server that encodes/decodes these values, I'll tear out that code and reuse it myself :)

I use this library to do all the low-level protocol buffer encoding: https://github.com/jskeet/protobuf-csharp-port

The server code to decode arguments is here: https://github.com/djungelorm/krpc/blob/master/src/kRPC/Service/Services.cs#L111

And to encode them is here: https://github.com/djungelorm/krpc/blob/master/src/kRPC/Service/Services.cs#L238

This code also uses some utility methods, which can be found here: https://github.com/djungelorm/krpc/blob/master/src/kRPC/Utils/ProtocolBuffers.cs

Hope that helps!

- - - Updated - - -

It's up on KerbalStuff so is probably just taking some time to update.

Looks like there is an issue with KerbalStuff/CKAN... working to fix it!

Share this post


Link to post
Share on other sites

A tiny bug which hopefully can easily be reproduced: I have two kRPC buttons.

Share this post


Link to post
Share on other sites
Valid concerns! I've updated the default configuration to make it more secure. It now only accepts connections from the local machine, and uses port 50000 by default.

With these settings the outside world shouldn't be able to connect to the server. (I'm not a network security expert, but I'm fairly certain about this!)

Assuming you have a standard home network setup (a router that does NAT to connect to the internet) the outside world will only be able to connect if both of the following are true:

1) your router is configured to "port forward" the port that the server listens on (home routers usually come preconfigured not to do this anyway)

2) the server is configured to accept connections from any IP address

Also, port 50000 is within the range of port numbers used for private/temporary use. If you're really worried, you can change this to anything in the range of 1024-65535 for a bit of security through obscurity :P

Enforcement of these settings for incoming connections (if they do get through the port forwarding on your router) is done using C#'s System.Net.Sockets.TcpListener class. So I'm relying on the security of Microsoft's implementation of the C# libraries rather than any of my code ;)

If you do decide to use it over the wider internet, I don't think doing so is particularly dangerous. All the data received over the connection is passed through this protocol buffers library. If any malformed messages are received, an exception is generated, and the RPC server returns an error message. Although, of course, use it over the internet at your own risk!

Well, if you're checking for IP after connection has been made it's too late. Either you have to bind to 127.0.0.1 to make it local only, and not to 'any' local port, or you have to validate a lot more than just the IP.

Also, I think you don't really have to worry much about the security in this case anyway, as majority of the use cases are in LAN only, and if there's an intruder/malware/spyware/trojan already in LAN, then it's also too late, and your software sec is the least concern for the victim.

Edited by Dre4dW0rm

Share this post


Link to post
Share on other sites

Trying to talk to KRPC with ProtoBuf.jl in Julia, and was about to decode a GetStatus request, but when I tried to take on a GetServices request (which is much longer the the length that can be described with UInt8), I'm wasn't sure how to handle the VarInt encoding of the header.

I also gave PyCall.jl to call the krpc interface, and it mostly works, but Streams seem to be a problem because of what seems to be how semantics of generators don't seem to automatically translate to Julia's generators (the values don't update). Would there be interest helping develop Julia RPC client as I am very new to Protocol buffers? There seems to be ProtoBuf.jl functionality that supports this (if you can implement your controller as a subtype of ProtoRpcController), and Julia has good support for metaprogramming that would seem useful for generating an interface, and I hope to use it to make a web interface like that of Telemachus.

Share this post


Link to post
Share on other sites

Hello,

I just wanted to inform you that I've created Ruby client for kRPC.

It's working pretty smoothly, with the only major feature missing being support for streaming.

I plan to develop it further, tho I'll be quite busy with other things for a few weeks.

For more see: https://github.com/TeWu/krpc-rb

I haven't yet a chance, so let me say Thank You djungelorm for creating this amazing mod :)

Share this post


Link to post
Share on other sites
Trying to talk to KRPC with ProtoBuf.jl in Julia, and was about to decode a GetStatus request, but when I tried to take on a GetServices request (which is much longer the the length that can be described with UInt8), I'm wasn't sure how to handle the VarInt encoding of the header.

You should read https://developers.google.com/protocol-buffers/docs/encoding#varints for description of varint encoding.

Here you have, how it is done in Python: https://github.com/google/protobuf/blob/v3.0.0-beta-1/python/google/protobuf/internal/decoder.py#L136

And here, how I've done varint receiving in my kRPC client: https://github.com/TeWu/krpc-rb/blob/0.2.0/lib/krpc/connection.rb#L55

You might also like to see this file from my implementation: https://github.com/TeWu/krpc-rb/blob/0.2.0/lib/krpc/protobuf_utils.rb

It's all about protobuf' value types encoding and decoding.

Edited by TeWu

Share this post


Link to post
Share on other sites
Well, if you're checking for IP after connection has been made it's too late. Either you have to bind to 127.0.0.1 to make it local only, and not to 'any' local port, or you have to validate a lot more than just the IP.

Also, I think you don't really have to worry much about the security in this case anyway, as majority of the use cases are in LAN only, and if there's an intruder/malware/spyware/trojan already in LAN, then it's also too late, and your software sec is the least concern for the victim.

The current behaviour is that, by default, the server indeed binds to 127.0.0.1. There is currently no way to bind the server to 'any'.

- - - Updated - - -

Hello,

I just wanted to inform you that I've created Ruby client for kRPC.

It's working pretty smoothly, with the only major feature missing being support for streaming.

I plan to develop it further, tho I'll be quite busy with other things for a few weeks.

For more see: https://github.com/TeWu/krpc-rb

I haven't yet a chance, so let me say Thank You djungelorm for creating this amazing mod :)

Sweet! If you like I can link to it from the first post and the documentation site. May be good to add a "third party" client libraries section :)

Share this post


Link to post
Share on other sites
Sweet! If you like I can link to it from the first post and the documentation site. May be good to add a "third party" client libraries section :)

Sure - I would like that.

Share this post


Link to post
Share on other sites

Is there anyway to execute a maneuver node created outside of kRPC? For example, if you created a maneuver node, could you write a kRPC script to execute the node that was created before starting the script without creating the maneuver node within kRPC? It looks like the only way kRPC recognized a node is if it is created within itself using control.addnode().

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.