Skip to content

Commit f601da6

Browse files
authored
Merge pull request #26 from jdlangs/docs
Add docstrings to exported types/functions
2 parents bc3b237 + 7100ba5 commit f601da6

File tree

5 files changed

+190
-23
lines changed

5 files changed

+190
-23
lines changed

src/gentypes.jl

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using Compat
44
import Compat: String, Symbol
55

6-
export @rosimport, rostypegen, rostypereset, gentypes, cleartypes
6+
export @rosimport, rostypegen, rostypereset
77

88
#Type definitions
99
#Composite types for internal use. Keeps track of the imported types and helps
@@ -55,7 +55,7 @@ const _ros_builtin_types = Dict{String, Symbol}(
5555
"string" => :String,
5656
"time" => :Time,
5757
"duration"=> :Duration,
58-
#Deprecated but supported
58+
#Deprecated by ROS but supported here
5959
"char" => :UInt8,
6060
"byte" => :Int8,
6161
)
@@ -65,11 +65,23 @@ const _ros_builtin_types = Dict{String, Symbol}(
6565
@compat abstract type AbstractSrv end
6666
@compat abstract type AbstractService end
6767

68-
#Rearranges the expression into a RobotOS._rosimport call. Input comes in as a
69-
#single package qualified expression, or as a tuple expression where the first
70-
#element is the same as the single expression case. Most of the code is just
71-
#error checking that the input takes that form.
68+
"""
69+
@rosimport
70+
71+
Import ROS message or service types into Julia. Call `rostypegen()` after all `@rosimport` calls.
72+
Package or type dependencies are also imported automatically as needed.
73+
74+
Example usages:
75+
```julia
76+
@rosimport geometry_msgs.msg.PoseStamped
77+
@rosimport sensor_msgs.msg: Image, Imu
78+
@rosimport nav_msgs.srv.GetPlan
79+
```
80+
"""
7281
macro rosimport(input)
82+
#Rearranges the expression into a RobotOS._rosimport call. Input comes in as a single package
83+
#qualified expression, or as a tuple expression where the first element is the same as the
84+
#single expression case. Most of the code is just error checking that the input takes that form.
7385
@assert input.head in [:tuple, :(.), :(:)] "Improper @rosimport input"
7486
if input.head == :tuple
7587
@assert isa(input.args[1], Expr) "Improper @rosimport input"
@@ -124,8 +136,13 @@ function _rosimport(package::String, ismsg::Bool, names::String...)
124136
end
125137
end
126138

127-
#Do the Julia type generation. This function is needed because we want to
128-
#create the modules in one go, rather than anytime @rosimport gets called
139+
"""
140+
rostypegen()
141+
142+
Initiate the Julia type generation process after importing some ROS types. Creates modules in `Main`
143+
with the same behavior as imported ROS modules in python. Should only be called once, after all
144+
`@rosimport` statements are done.
145+
"""
129146
function rostypegen()
130147
global _rospy_imports
131148
pkgdeps = _collectdeps(_rospy_imports)
@@ -135,9 +152,12 @@ function rostypegen()
135152
end
136153
end
137154

138-
#Reset type generation process to start over with @rosimport. Does not remove
139-
#already generated modules! They will be replaced when rostypegen is called
140-
#again.
155+
"""
156+
rostypereset()
157+
158+
Clear out the previous `@rosimport`s, returning the type generation to its original state. Cannot do
159+
anything about already generated modules in `Main`.
160+
"""
141161
function rostypereset()
142162
global _rospy_imports
143163
global _rospy_objects

src/pubsub.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ export Publisher, Subscriber, publish
33

44
using Compat
55

6+
"""
7+
Publisher{T}(topic; kwargs...)
8+
Publisher(topic, T; kwargs...)
9+
10+
Create an object to publish messages of type `T` on a topic. Keyword arguments are directly passed
11+
to rospy.
12+
"""
613
type Publisher{MsgType<:AbstractMsg}
714
o::PyObject
815

@@ -16,10 +23,23 @@ end
1623
Publisher{MT<:AbstractMsg}(topic::AbstractString, ::Type{MT}; kwargs...) =
1724
Publisher{MT}(ascii(topic); kwargs...)
1825

26+
"""
27+
publish(p::Publisher{T}, msg::T)
28+
29+
Publish `msg` on `p`, a `Publisher` with matching message type.
30+
"""
1931
function publish{MT<:AbstractMsg}(p::Publisher{MT}, msg::MT)
2032
pycall(p.o["publish"], PyAny, convert(PyObject, msg))
2133
end
2234

35+
"""
36+
Subscriber{T}(topic, callback, cb_args=(); kwargs...)
37+
Subscriber(topic, T, callback, cb_args=(); kwargs...)
38+
39+
Create a subscription to a topic with message type `T` with a callback to use when a message is
40+
received, which can be any callable type. Extra arguments provided to the callback when invoked
41+
can be provided in the `cb_args` tuple. Keyword arguments are directly passed to rospy.
42+
"""
2343
type Subscriber{MsgType<:AbstractMsg}
2444
callback
2545
callback_args::Tuple

src/rospy.jl

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,30 @@ export init_node, is_shutdown, spin,
33
get_param, has_param, set_param, delete_param,
44
logdebug, loginfo, logwarn, logerr, logfatal
55

6-
#General rospy functions
6+
"""
7+
init_node(name; args...)
8+
9+
Initialize this node, registering it with the ROS master. All arguments are passed on directly to
10+
the rospy init_node function.
11+
"""
712
init_node(name::AbstractString; args...) =
813
__rospy__[:init_node](ascii(name); args...)
14+
15+
"""
16+
is_shutdown()
17+
18+
Return the shutdown status of the node.
19+
"""
920
is_shutdown() = __rospy__[:is_shutdown]()
21+
1022
get_published_topics() = __rospy__[:get_published_topics]()
1123
get_ros_root() = __rospy__[:get_ros_root]()
1224

25+
"""
26+
spin()
27+
28+
Block execution and process callbacks/service calls until the node is shut down.
29+
"""
1330
function spin()
1431
#Have to make sure both Julia tasks and python threads can wake up so
1532
#can't just call rospy's spin
@@ -19,6 +36,12 @@ function spin()
1936
end
2037

2138
#Parameter server API
39+
"""
40+
get_param(param_name, default=nothing)
41+
42+
Request the value of a parameter from the parameter server, with optional default value. If no
43+
default is given, throws a `KeyError` if the parameter cannot be found.
44+
"""
2245
function get_param(param_name::AbstractString, def=nothing)
2346
try
2447
if def == nothing
@@ -30,17 +53,36 @@ function get_param(param_name::AbstractString, def=nothing)
3053
throw(KeyError(pycall(pybuiltin("str"), PyAny, ex.val)[2:end-1]))
3154
end
3255
end
56+
57+
"""
58+
set_param(param_name, val)
59+
60+
Set the value of a parameter on the parameter server.
61+
"""
3362
set_param(param_name::AbstractString, val) =
3463
__rospy__[:set_param](ascii(param_name), val)
64+
65+
"""
66+
has_param(param_name)
67+
68+
Return a boolean specifying if a parameter exists on the parameter server.
69+
"""
3570
has_param(param_name::AbstractString) =
3671
__rospy__[:has_param](ascii(param_name))
72+
73+
"""
74+
delete_param(param_name)
75+
76+
Delete a parameter from the parameter server. Throws a `KeyError` if no such parameter exists.
77+
"""
3778
function delete_param(param_name::AbstractString)
3879
try
3980
__rospy__[:delete_param](ascii(param_name))
4081
catch ex
4182
throw(KeyError(pycall(pybuiltin("str"), PyAny, ex.val)[2:end-1]))
4283
end
4384
end
85+
4486
#Doesn't work for some reason
4587
#rospy_search_param(param_name::AbstractString) =
4688
# __rospy__[:rospy_search_param](ascii(param_name))
@@ -53,6 +95,14 @@ logwarn(msg, args...) = __rospy__[:logwarn](msg, args...)
5395
logerr(msg, args...) = __rospy__[:logerr](msg, args...)
5496
logfatal(msg, args...) = __rospy__[:logfatal](msg, args...)
5597

98+
"""
99+
logdebug, loginfo, logwarn, logerr, logfatal
100+
101+
Call the rospy logging system at the corresponding message level, passing a message and other
102+
arguments directly.
103+
"""
104+
logdebug, loginfo, logwarn, logerr, logfatal
105+
56106
#Node information
57107
get_name() = __rospy__[:get_name]()
58108
get_namespace() = __rospy__[:get_namespace]()

src/services.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ export Service, ServiceProxy, wait_for_service
33

44
using Compat
55

6+
"""
7+
ServiceProxy{T}(name; kwargs...)
8+
ServiceProxy(name, T; kwargs...)
9+
10+
Create a proxy object used to invoke a remote service. Use `srv_proxy(msg_request)` with the object
11+
to invoke the service call. Keyword arguments are directly passed to rospy.
12+
"""
613
type ServiceProxy{SrvType <: AbstractService}
714
o::PyObject
815

@@ -32,6 +39,13 @@ end
3239
resp
3340
end
3441

42+
"""
43+
Service{T}(name, callback; kwargs...)
44+
Service(name, T, callback; kwargs...)
45+
46+
Create a service object that can receive requests and provide responses. The callback can be of
47+
any callable type. Keyword arguments are directly passed to rospy.
48+
"""
3549
type Service{SrvType <: AbstractService}
3650
handler
3751
srv_obj::PyObject
@@ -71,6 +85,12 @@ function Service{ST<:AbstractService}(name::AbstractString, srv::Type{ST}, handl
7185
Service{ST}(ascii(name), handler; kwargs...)
7286
end
7387

88+
"""
89+
wait_for_service(srv_name; kwargs...)
90+
91+
Block until the specified service is available. Keyword arguments are directly passed to rospy.
92+
Throws an exception if the waiting timeout period is exceeded.
93+
"""
7494
function wait_for_service(service::AbstractString; kwargs...)
7595
try
7696
__rospy__[:wait_for_service](ascii(service); kwargs...)

src/time.jl

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ export Time, Duration, Rate, to_sec, to_nsec, get_rostime, rossleep
88
#Time type definitions
99
@compat abstract type TVal end
1010

11+
"""
12+
Time(secs, nsecs), Time(), Time(t::Real)
13+
14+
Object representing an absolute time from a fixed past reference point at nanosecond precision.
15+
16+
Basic arithmetic can be performed on combinations of `Time` and `Duration` objects that make sense.
17+
For example, if `t::Time` and `d::Duration`, `t+d` will be a `Time`, `d+d` a Duration`, `t-d` a
18+
`Time`, `d-d` a `Duration`, and `t-t` a `Duration`.
19+
"""
1120
immutable Time <: TVal
1221
secs::Int32
1322
nsecs::Int32
@@ -19,6 +28,15 @@ end
1928
Time() = Time(0,0)
2029
Time(t::Real) = Time(t,0)
2130

31+
"""
32+
Duration(secs, nsecs), Duration(), Duration(t::Real)
33+
34+
Object representing a relative period of time at nanosecond precision.
35+
36+
Basic arithmetic can be performed on combinations of `Time` and `Duration` objects that make sense.
37+
For example, if `t::Time` and `d::Duration`, `t+d` will be a `Time`, `d+d` a `Duration`, `t-d` a
38+
`Time`, `d-d` a `Duration`, and `t-t` a `Duration`.
39+
"""
2240
immutable Duration <: TVal
2341
secs::Int32
2442
nsecs::Int32
@@ -45,7 +63,6 @@ function _canonical_time(secs, nsecs)
4563
(secs32 + addsecs, crnsecs)
4664
end
4765

48-
#Temporal arithmetic
4966
+(t1::Time, t2::Duration) = Time( t1.secs+t2.secs, t1.nsecs+t2.nsecs)
5067
+(t1::Duration, t2::Time) = Time( t1.secs+t2.secs, t1.nsecs+t2.nsecs)
5168
+(t1::Duration, t2::Duration) = Duration(t1.secs+t2.secs, t1.nsecs+t2.nsecs)
@@ -62,14 +79,44 @@ convert(::Type{PyObject}, t::Time) = __rospy__[:Time]( t.secs,t.nsecs)
6279
convert(::Type{PyObject}, t::Duration) = __rospy__[:Duration](t.secs,t.nsecs)
6380

6481
#Real number conversions
82+
"""
83+
to_sec(t)
84+
85+
Return the value of a ROS time object in absolute seconds (with nanosecond precision)
86+
"""
6587
to_sec{T<:TVal}(t::T) = t.secs + 1e-9*t.nsecs
88+
89+
"""
90+
to_nsec(t)
91+
92+
Return the value of a ROS time object in nanoseconds as an integer.
93+
"""
6694
to_nsec{T<:TVal}(t::T) = 1_000_000_000*t.secs + t.nsecs
6795
convert{T<:TVal}(::Type{Float64}, t::T) = to_sec(t)
6896

6997
#Comparisons
70-
=={T<:TVal}(t1::T, t2::T) = (t1.secs == t2.secs) && (t1.nsecs == t2.nsecs)
98+
=={T<:TVal}(t1::T, t2::T) = (t1.secs == t2.secs) && (t1.nsecs == t2.nsecs)
7199
isless{T<:TVal}(t1::T, t2::T) = to_nsec(t1) < to_nsec(t2)
72100

101+
"""
102+
Rate(hz::Real), Rate(d::Duration)
103+
104+
Used to allow a loop to run at a fixed rate. Construct with a frequency or `Duration` and use with
105+
`rossleep` or `sleep`. The rate object will record execution time of other work in the loop and
106+
modify the sleep time to compensate, keeping the loop rate as consistent as possible.
107+
"""
108+
type Rate
109+
duration::Duration
110+
last_time::Time
111+
end
112+
Rate(d::Duration) = Rate(d, get_rostime())
113+
Rate(hz::Real) = Rate(Duration(1.0/hz), get_rostime())
114+
115+
"""
116+
get_rostime()
117+
118+
Return the current ROS time as a `Time` object.
119+
"""
73120
function get_rostime()
74121
t = try
75122
__rospy__[:get_rostime]()
@@ -78,8 +125,20 @@ function get_rostime()
78125
end
79126
convert(Time, t)
80127
end
128+
129+
"""
130+
RobotOS.now()
131+
132+
Return the current ROS time as a `Time` object.
133+
"""
81134
now() = get_rostime()
82135

136+
"""
137+
rossleep(t)
138+
139+
Sleep and process callbacks for a number of seconds implied by the type and value of `t`, which may
140+
be a real-value, a `Duration` object, or a `Rate` object.
141+
"""
83142
function rossleep(td::Duration)
84143
#Busy sleep loop needed to allow both julia and python async activity
85144
tnsecs = to_nsec(td)
@@ -91,15 +150,6 @@ function rossleep(td::Duration)
91150
end
92151
rossleep(t::Real) = rossleep(Duration(t))
93152

94-
sleep(t::Duration) = rossleep(t)
95-
96-
type Rate
97-
duration::Duration
98-
last_time::Time
99-
end
100-
Rate(d::Duration) = Rate(d, get_rostime())
101-
Rate(hz::Real) = Rate(Duration(1.0/hz), get_rostime())
102-
103153
function rossleep(r::Rate)
104154
ctime = get_rostime()
105155
if r.last_time > ctime
@@ -113,4 +163,11 @@ function rossleep(r::Rate)
113163
r.last_time = ctime
114164
end
115165
end
166+
167+
"""
168+
sleep(t::Duration), sleep(t::Rate)
169+
170+
Call `rossleep` with a `Duration` or `Rate` object. Use `rossleep` to specify sleep time directly.
171+
"""
172+
sleep(t::Duration) = rossleep(t)
116173
sleep(t::Rate) = rossleep(t)

0 commit comments

Comments
 (0)