bluenviron / goroslib Goto Github PK
View Code? Open in Web Editor NEWROS client library for the Go programming language
License: MIT License
ROS client library for the Go programming language
License: MIT License
OS
Architecture
Topics aren't removed from the ROS master topic list on normal node Shutdown (SIGTERM)
this also applies to things like node name.
Hi,
Thanks for your work ! I was looking how to build lightweight nodes in Go.
I'm using ROS Melodic
Right now, I'm trying to implement a basic service client/provider. I did as the examples says.
But I can't make them communicate with each others.
Error: lookupService: server returned an error (-1): no provider
Also, when I'm using rosnode
and rosservice
and use list
I've got a double slash prefix.
$ rosnode list
//node_name
$ rosservice list
//service_name
I can't call them or get any infos. They seems to be unknown or corrupt in some way.
Any ideas what's going on ?
goroslib is currently works only with IPv4 networks.
Would be great to add support for IPv6 networks as well.
Hello,
I wanted to use this package in my work, but I met a problem with custom services.
When I launch the example "serviceprovider-custom.go" and try to call this service through the CLI, I get this:
"ERROR: Unable to load type [my_package/TestService].
Have you typed 'make' in [my_package]?"
The error is the same for custom messages.
How can it be solved?
I would appreciate any help!
A client library should log debug and info messages to /rosout.
Good morning.
The commit that you refereed fixed the error that I was noticing when running multimaster_fkie and goroslib. However, it seems that now, after a while, the subscriber stops receiving information. It happens after approximately 10 minutes. I tried with a simple string just to test and the problem persists. Interesting bug.
Best,
Filipe Pinto
Hello, I wonder if it it is possible to pass an extra parameter to the subscriber callback. Does goroslib allow this somehow? What is the appropriate way of doing this? I checked the SubscriberConf struct definition,
https://github.com/aler9/goroslib/blob/978eeb6e825ee627aa2b33a765024ae9991139b2/subscriber.go#L24
and it does not seem have any field dedicated to this possibility. Is it possible to achieve this through the interface destined for the callback? The NewSubscriber function seems to limit this a bit
https://github.com/aler9/goroslib/blob/978eeb6e825ee627aa2b33a765024ae9991139b2/subscriber.go#L78
Context: my use case requires multiple topic subscriptions of the same type. For that I need to know to which topic, each message received belongs to. With rospy I would simply do something similar to what is suggested in the answer of this post https://answers.ros.org/question/231492/passing-arguments-to-callback-in-python/.
Apologies in advance if this is a golang specific question.
Best regards,
João Aguizo
Hi aler9,
I was planning on using your library in my senior design project, but I came across a bug.
I tried publishing a topic from one of the examples (examples/publisher.go) and subscribing to it from rostopic echo
and it gave me the following error message.
ERROR: Cannot load message class for [goroslib/Msg]. Are your messages built?
rostopic list -v
also shows the type of the message being [goroslib/Msg]
even though the node should be publishing a sensor_msg/Imu
.
This can be reproduced using the following docker commands
Start the ros core:
docker run --rm -it --network=host --name=ros ros:melodic-ros-core-bionic roscore
Compile and start the publisher:
docker run --rm -it --network=host golang:1.13 sh -c "git clone https://github.com/aler9/goroslib && cd goroslib && go run examples/publisher.go"
Here I try to subscribe using rostopic
docker exec -it ros bash -c "source /opt/ros/melodic/setup.bash && rostopic echo /test_pub"
Here we can the type is being reported as goroslib/Msg
insead of sensor_msg/Imu
docker exec -it ros bash -c "source /opt/ros/melodic/setup.bash && rostopic list -v"
I ended up using github.com/fetchrobotics/rosgo so it's not critical, but I thought I'd let you know.
I don't think it matters too much given that I gave you a docker example but I'm running docker on an Ubuntu 18.04 VM with docker 19.03.8.
Thanks,
Jesse Stevenson
Great library. Maybe this is available and I'm just really dumb, but would it be possible to implement cancelGoal and cancelAllGoals methods for the simple action client?
**Connection drop error while subscribing /diagnostics
on ROS melodic. **
ERROR] [1605789975.048534337]: Client [/goroslib-sub] wants topic /diagnostics to have datatype/md5sum [diagnostic_msgs/DiagnosticArray/009ab8ab4fe239b91b7cff4869b68b68], but our version has [diagnostic_msgs/DiagnosticArray/60810da900de1dd6ddd437c3503511da]. Dropping connection.
### Versions:-
golang 1.15.2 windows/amd64
ROS melodic
code:-
import (
"fmt"
"github.com/aler9/goroslib"
"github.com/aler9/goroslib/pkg/msgs/diagnostic_msgs"
)
func setDiagMessages(val *diagnostic_msgs.DiagnosticArray) {
fmt.Println(val)
}
func main() {
n, err := goroslib.NewNode(goroslib.NodeConf{
Name: "/goroslib-sub",
MasterHost: MASTER,
})
if err != nil {
panic(err)
}
defer n.Close()
sub, err := goroslib.NewSubscriber(goroslib.SubscriberConf{
Node: n,
Topic: "/diagnostics",
Callback: setDiagMessages,
})
if err != nil {
panic(err)
}
defer sub.Close()
// freeze main loop
select {}
}
Does this library support ROS2? if not then any plans to support ROS2.
Thanks in advance
OS
Architecture
I'm trying to drop a bagfile recorded from radar data topics published by goroslib into Webviz, but when I do, Webviz tells me that the bagfile has empty connections. The bagfile runs fine in rviz. There seems to be a problem with inconsistent md5 checksums.
Thanks in advance for answers! I will forward the whole error message below:
This bag has some empty connections, which Webviz does not currently support. We'll try to play the remaining topics. Details:
[{"offset":66778612,"dataOffset":66778654,"end":66778800,"length":188,"conn":1,"topic":"/tf","type":"tf2_msgs/TFMessage","md5sum":"94810edda583a504dfda3829e70d7eec","messageDefinition":"","callerid":"/PC2_test_pub","latching":false},{"offset":66778800,"dataOffset":66778852,"end":66779019,"length":219,"conn":2,"topic":"/PC2_Radar_FL","type":"sensor_msgs/PointCloud2","md5sum":"1158d486dd51d683ce2f1be655c3c181","messageDefinition":"","callerid":"/PC2_Radar_testNode","latching":false}]
When i use this lib to pusblish costom msgs to another CPP node, The CPP node tell me the datatype/md5sum check failed, the log as bellow:
[ERROR] [1602764150.921571564]: Client [/avatar] wants topic /topic/response/signal/message to have datatype/md5sum [atris_msgs/SignalMessage/21bf35dedac23c2dd7049256f5f2f971], but our version has [atris_msgs/SignalMessage/47da1d8e018fea14775e1f7b4683149a]. Dropping connection.
Does this port should work on Windows?
I have successfully cross-compiled a subscriber and publisher for Windows and run them on a Windows computer on the same network than an Ubuntu box with a ROS master.
The new nodes show up in rosnode list
but even by supplying correct MasterHost
in the node constructor, no message are passing.
I have disabled the firewall on the Windows side.
But before digging further, I wanted to know if it is supposed to work on Windows or not.
For me, Windows support would be a major feature because I would be able to easily compile Windows static binaries of ROS nodes from Linux and with a single binary file to deploy.
Originally posted by Beril-1 September 28, 2021
Hello!
By following the examples provided in goroslib, I implemented a SimpleActionServer that waits for the user input which may take a bit of time. My problem is when I do "rostopic echo to the /status" the status array is being cleaned and the goal is being deleted after 5 seconds and I can not conclude the process. I saw in goroslib a configuration called "DeleteGoalAfter" in the NewSimpleAction function adjusted to 5 seconds (https://github.com/aler9/goroslib/blob/6f6095873d06d5e9c6146d1cb4ae6560983fe547/actionserver.go#L248).
May it be the issue? What is the correct way of implementing the simpleActionServer to keep the goals? I would be glad if you could help. Thank you!
Cheers,
Beril
Hello,
I have an issue when I try to launch Go nodes with roslaunch.
Basically, when I use a construction like roslaunch test test.launch
, everything works fine, but
when I define a port like roslaunch -p 11315 test test.launch
, the Go node crushes with the error:
unable to solve master address: lookup tcp/11315/: Servname not supported for ai_socktype [monitor_app-2] process has died [pid 54703, exit code 1, cmd .....
, meanwhile python nodes work well.
I have figured out a particular solution. If I add a line inside a Go node os.Setenv("ROS_MASTER_URI", "http://localhost:11315")
before node creation, the Go node starts working without errors.
Is it possible to make Go nodes behaving like python ones?
OS
Architecture
Description
It seems that the message_definition
header is "missing" from the HeaderPublisher
. From what I can gather from here it shouldn't be needed (which seems weird to me...) but the documentation is from 2013 so might not be up-to-date.
Looking at ros_comm, it seems the message_definition
is expected to be included in both publisher and subscriber (look in this test for example) and my manual tests seem to confirm it.
The reason this is an issue for me is that Foxglove Studio uses the message_definition
to determine how to parse an incoming message. Since this is missing all messages become "empty" as well and an error is thrown. It works as expected for nodes using the official libraries which makes me think it is within spec to include it.
What do you think? Would it be feasible to add the message_definition
to the header field? This is needed for me to be able to use node-to-node communication without using the ROS bridge in Foxglove Studio.
I got an panic log as follow:
panic: lookupService: server returned an error (-1): no provider
goroutine 1 [running]:
main.main()
/home/goroslib/examples/serviceclient.go:45 +0x3fb
Originally posted by sniperZj August 27, 2021
If inscribe
I'm playing with this lib and trying to figure out why pub.Write is blocking my code from continuing
My hacked together code
func onMessage(msg *sensor_msgs.Joy) {
fmt.Println("Incoming: %+v\n", msg)
x_float64 := msgs.Float64(float64(msg.Axes[0]))
y_float64 := msgs.Float64(float64(msg.Axes[1]))
linearVector := geometry_msgs.Vector3{X: x_float64, Y: y_float64}
rawMove := geometry_msgs.Twist{Linear: linearVector, Angular: linearVector}
stampedMove := geometry_msgs.TwistStamped{Header: msg.Header, Twist: rawMove}
pubTopic.Write(stampedMove)
fmt.Println("Handled Message")
}
func main() {
n, err := goroslib.NewNode(goroslib.NodeConf{
Name: "/goroslib",
MasterHost: "donkeycar",
})
if err != nil {
panic(err)
}
fmt.Println("Connected to Master")
defer n.Close()
// create a subscriber
subTopic, err := goroslib.NewSubscriber(goroslib.SubscriberConf{
Node: n,
Topic: "/joy",
Callback: onMessage,
})
if err != nil {
panic(err)
}
fmt.Println("Connected to Subscriber Topic")
defer subTopic.Close()
pubTopic, err := goroslib.NewPublisher(goroslib.PublisherConf{
Node: n,
Topic: "/actuator",
Msg: &geometry_msgs.TwistStamped{},
Latch: false,
})
if err != nil {
panic(err)
}
fmt.Println("Connected to Publisher Topic")
defer pubTopic.Close()
infty := make(chan int, 100)
<-infty
}
If I comment out the pubTopic.Write(stampedMove)
, the code will continuously update and print a stream of commands to my console. However, when calling write, it will receive the first event and than halt at the write step, and block any events from being written the console.
As far as I can tell, I do not see any sign of the message getting to a node that is subscribed to the topic.
OS
Architecture
When using the msg-import
command constants of type string are not handled property.
For example ROS definition:
# A simple ROS message definition
string CONSTANT1=CONSTANT_VALUE_1
string source
The following invalid Go code is generated:
package main //nolint:golint
import (
"github.com/aler9/goroslib/pkg/msg"
)
const (
Example1_CONSTANT1 string = CONSTANT_VALUE_1 //nolint:golint
)
type Example1 struct { //nolint:golint
msg.Package `ros:"ocu_msgs"`
msg.Definitions `ros:"string CONSTANT1=CONSTANT_VALUE_1"`
Source string//nolint:golint
}
The initialization value for Example1_CONSTANT1
is missing quotations, it should be "CONSTANT_VALUE_1"
A separate but perhaps related issue, for this example ROS definition file:
# A simple ROS message definition
string CONSTANT1="CONSTANT_VALUE_1"
string source
The following Go code is generated:
package main //nolint:golint
import (
"github.com/aler9/goroslib/pkg/msg"
)
const (
Example2_CONSTANT1 string = "CONSTANT_VALUE_1" //nolint:golint
)
type Example2 struct { //nolint:golint
msg.Package `ros:"ocu_msgs"`
msg.Definitions `ros:"string CONSTANT1="CONSTANT_VALUE_1""`
Source string//nolint:golint
}
The problem here is more subtle, the struct tag for msg.Definitions
is invalid because there are unescaped quotation marks. Instead is should be:
msg.Definitions `ros:"string CONSTANT1=\"CONSTANT_VALUE_1\""`
Hello again! Thanks for fixing my last issue fairly quickly, this time I'm back with a smaller issue.
While testing a few ROS services created with goroslib, I noticed that the created services don't work with rosservice info
and rosservice call
(and possibly others). Trying either of those commands will return a cryptic python error, suggesting the connection is broken.
This doesn't happen with regular clients (at least goroslib and rospy), but can still be annoying during testing.
This can be reproduced with docker (or alternatively by running the example code and doing rosservice ...
on an Ubuntu install). First run ros:
docker run -it --network=host --name=ros ros:noetic-ros-core roscore
Then start the example (in a new terminal):
docker run --rm -it --network=host golang:1.15 sh -c "git clone https://github.com/aler9/goroslib && cd goroslib && go run examples/serviceprovider.go"
Finally, run either info or call (in a new terminal):
docker exec -it ros bash -c "source /opt/ros/noetic/setup.bash && rosservice info /test_srv"
docker exec -it ros bash -c "source /opt/ros/noetic/setup.bash && rosservice call /test_srv '{data: false}'"
The final commands will give you something along the lines of:
Traceback (most recent call last):
File "/opt/ros/noetic/bin/rosservice", line 35, in <module>
rosservice.rosservicemain()
File "/opt/ros/noetic/lib/python3/dist-packages/rosservice/__init__.py", line 741, in rosservicemain
_rosservice_cmd_info(argv)
File "/opt/ros/noetic/lib/python3/dist-packages/rosservice/__init__.py", line 708, in _rosservice_cmd_info
_rosservice_info(name)
File "/opt/ros/noetic/lib/python3/dist-packages/rosservice/__init__.py", line 301, in _rosservice_info
t = get_service_type(service_name)
File "/opt/ros/noetic/lib/python3/dist-packages/rosservice/__init__.py", line 147, in get_service_type
return get_service_headers(service_name, service_uri).get('type', None)
File "/opt/ros/noetic/lib/python3/dist-packages/rosservice/__init__.py", line 124, in get_service_headers
return rosgraph.network.read_ros_handshake_header(s, BufferType(), 2048)
File "/opt/ros/noetic/lib/python3/dist-packages/rosgraph/network.py", line 359, in read_ros_handshake_header
raise ROSHandshakeException("connection from sender terminated before handshake header received. %s bytes were received. Please check sender for additional details."%b.tell())
rosgraph.network.ROSHandshakeException: connection from sender terminated before handshake header received. 0 bytes were received. Please check sender for additional details.
I believe the fix is relatively straightforward. First serviceprovider.go
will have to be changed (lines 159-162) to allow for a wildcard hash (similarly to publisher.go
at line 314-317):
if req.header.Md5sum != "*" && req.header.Md5sum != sp.srvMd5 {
eq.conn.Close()
continue
}
Furthermore, the Type
header at line 169 is now hardcoded to goroslib/Service
, but it seems this header is used by rosservice
to determine the type of the service. I'm no expert, but it seems this header is not used/ignored by goroslib and rospy, so that's why it works without problems for those clients.
I can think of a few solutions. You could try to deduce the type from the request and response types (which would then need to follow the <type>Req/Res
scheme), but this would impose restrictions on all users, so not a big fan of this one. Another option would be to keep the currently hardcoded value as a default, but allow users to override it. I'll leave it up to you to think of a nice solution for this one.
Hi there, I don't know much Go, but I have worked with ROS in C++ and found myself working "around" that framework, i.e. it was in most cases easier to implement the functionality needed myself, than use the monstrous ROS API. So this is great, a really great idea!
For my project I need to subscribe to a tf2 message, which is itself nothing more than a array of geometry_msgs/TransfromStamped. So how do I do that?
I tried
package main
import (
"fmt"
"github.com/aler9/goroslib"
"github.com/aler9/goroslib/msgs/geometry_msgs"
)
func callback(msg *[]geometry_msgs.TransformStamped) {
fmt.Printf("%+v", msg)
}
func main() {
n, err := goroslib.NewNode(goroslib.NodeConf{
Name: "/glassdetection",
MasterHost: "127.0.0.1",
})
if err != nil {
panic(err)
}
defer n.Close()
sub, err := goroslib.NewSubscriber(goroslib.SubscriberConf{
Node: n,
Topic: "/tf",
Callback: callback,
})
if err != nil {
panic(err)
}
defer sub.Close()
infty := make(chan int)
<-infty
}
But that errors with panic: Message must be a pointer to a struct
.
So then I wrote a TFMessage.msg
:
import (
"github.com/aler9/gosroslib/msgs"
)
type TFMessage struct {
Transforms []geometry_msgs.TransformStamped
}
and ran msg-import
on it, but it failed with ERR: line does not contain 2 fields.
How can I make this work?
(I could of course, write a node in C++ that subscribes to the TFMessage, and then publishes the individual TransfromStamped s as individual message and subscribe to them, but that is soo hacky.)
PS: OT: Add to the main page on installation that the env variable GO111MODULE should be set to on. That took me quite some time to figure out.
OS
Architecture
When subscribed to a topic no messages are received.
Note: the topic has been verified to be actively publishing using the rostopic echo /topic
command.
Issue 1: The subscriber silently ignores errors that are returned during execution of the TCP protocol:
See: https://github.com/aler9/goroslib/blob/499e979f2f583a2fbffad8ee6773b4524a41c9bf/subscriberpub.go#L60-L63
This made if much more difficult to identify the actual problem. I've had a brief look at the code and it looks like there is no clear way to report these errors. (Hoping you may have some ideas?) However, it would be good if these could at least be logged.
Issue 2: The TCP protocol runInnerTCP
returns a "wrong topic" error. In our case the publisher of the topic does not does not include the topic in their reply header. (As it is not strictly required by the spec: http://wiki.ros.org/ROS/TCPROS)
If the response from the publisher does not include the topic, then this check should not be done, potentially fixed by checking if the topic is empty, for example:
if outHeader.Topic != "" && outHeader.Topic != sp.sub.conf.Node.absoluteTopicName(sp.sub.conf.Topic) {
return fmt.Errorf("wrong topic")
}
In addition it would be good to add a check for message type (along with the MD5 sum which you already have), which are both required by the spec.
This publisher causing this error uses is a custom ROS implementation that follows the spec more closely then the standard/official ROS tools and libraries.
Using Melodic on Linux
go version go1.14.2 linux/arm64
imgStream := make(chan *sensor_msgs.CompressedImage, 100)
subTopic, err = goroslib.NewSubscriber(goroslib.SubscriberConf{
Node: n,
Topic: "/output/image_raw/CompressedImage",
Callback: func(msg *sensor_msgs.CompressedImage) {
imgStream <- msg
},
})
if err != nil {
panic(err)
}
fmt.Println("Connected to Subscriber Topic")
defer subTopic.Close()
Connected to Subscriber Topic
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x6c52d4]
goroutine 30 [running]:
github.com/aler9/goroslib.(*subscriberPublisher).run.func4(0x400028e960, 0x400028a0d8, 0x4000210080, 0x400028c480)
/home/jkim/go/src/github.com/aler9/goroslib/subscriber-pub.go:105 +0x4c
created by github.com/aler9/goroslib.(*subscriberPublisher).run
/home/jkim/go/src/github.com/aler9/goroslib/subscriber-pub.go:103 +0x2a0
exit status 2
rqt_images shows the video frames rendering on that topic just fine.
Subscribing just to /output/image_raw
does not panic, but nothing comes through on the topic
Hi!
I have discovered your work through the recent Ubuntu blog post. Nice job!
You have done a great documentation job and I like how you test the issues in simple docker containers as in this comment #2 (comment) 👍
My first try was to test a simple subscriber like the one in the examples and it seems to never receive a message from rostopic pub
. But I have noticed that if I give a rate -r 1
, the messages start to appear and from the Seq: 1
so all messages seem to be received.
The issue is that sometimes, a node only waits for one message and not repeated messages so this behavior can be an issue.
Steps to reproduce:
docker run --rm -it --network=host --name=roscore ros:melodic-ros-core-bionic roscore
docker run --rm -it --network=host golang:1.14 sh -c "git clone https://github.com/aler9/goroslib && cd goroslib && go run examples/subscriber.go"
rostopic echo
to check that the message is published
docker run --rm -it --network=host --name=rostopic_echo ros:melodic-ros-core-bionic rostopic echo /test_pub
rostopic pub --once
docker run --rm -it --network=host --name=rostopic_pub ros:melodic-ros-core-bionic rostopic pub --once /test_pub sensor_msgs/Imu "header:
seq: 0
stamp: {secs: 0, nsecs: 0}
frame_id: ''
orientation: {x: 0.0, y: 0.0, z: 0.0, w: 0.0}
orientation_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
angular_velocity: {x: 0.0, y: 0.0, z: 0.0}
angular_velocity_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
linear_acceleration: {x: 0.0, y: 0.0, z: 0.0}
linear_acceleration_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]"
And here, I get no message from in the go subscriber console.
Now, if we publish with a rate, replace 4. with:
docker run --rm -it --network=host --name=rostopic_pub ros:melodic-ros-core-bionic rostopic pub -r 1 /test_pub sensor_msgs/Imu "header:
seq: 0
stamp: {secs: 0, nsecs: 0}
frame_id: ''
orientation: {x: 0.0, y: 0.0, z: 0.0, w: 0.0}
orientation_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
angular_velocity: {x: 0.0, y: 0.0, z: 0.0}
angular_velocity_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
linear_acceleration: {x: 0.0, y: 0.0, z: 0.0}
linear_acceleration_covariance: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]"
It works!
Let me begin by saying I'm a beginner with ROS, so if this issue is just because of something I'm doing wrong, let me know. If I missed something in the docs, or this is just not supported, also let me know :)
I was unable to find something about namespaces, so I just assumed we are supposed to do this by having an appropriate node name. For example: /namespace/node
. It looks like this is working, as the ros master will successfully remap new subscribers/publishers to the namespace. So creating a subscriber which subscribes to /topic
on a node called /namespace/node
, will successfully subscribe to /namespace/topic
, and the same goes for a publisher.
Unfortunately, goroslib doesn't seem to handle namespaces that well. When using namespaces, a goroslib.Subscriber
subscribed to /topic
(which will be remapped to /namespace/topic
), will successfully receive messages from already existing publishers. However, this is not the case for publishers created after said subscriber.
To demonstrate this I have written a small test:
package main
import (
"fmt"
"time"
)
func main() {
// No namespace
test("")
// Namespace
test("namespace/")
}
func test(namespace string) {
fmt.Printf("Using namespace '%s'\n", namespace)
// Create publisher before the subscriber, this should work
p1 := NewPub(fmt.Sprintf("/%spub1", namespace))
// Create the actual subscriber
s := NewSub(fmt.Sprintf("/%ssub", namespace))
// Create a publisher after the subscriber is running, the subscriber will not receive updates from this one
p2 := NewPub(fmt.Sprintf("/%spub2", namespace))
time.Sleep(time.Second * 2)
p1.Publisher.Write(&Message{
Msg: "Msg before sub",
})
p2.Publisher.Write(&Message{
Msg: "Msg after sub",
})
time.Sleep(time.Second)
s.Close()
p1.Close()
p2.Close()
fmt.Printf("---\n")
}
package main
import (
"github.com/aler9/goroslib"
)
// Creates a publisher on the '/topic' topic.
type Pub struct {
Node *goroslib.Node
Publisher *goroslib.Publisher
}
func NewPub(name string) *Pub {
p := &Pub{}
var err error
p.Node, err = goroslib.NewNode(goroslib.NodeConf{
MasterHost: "localhost",
MasterPort: 11311,
Name: name,
})
if err != nil {
panic(err)
}
p.Publisher, err = goroslib.NewPublisher(goroslib.PublisherConf{
Node: p.Node,
Topic: "/topic",
Msg: &Message{},
})
return p
}
func (p *Pub) Close() {
if err := p.Publisher.Close(); err != nil {
panic(err)
}
if err := p.Node.Close(); err != nil {
panic(err)
}
}
/// main.go
package main
import (
"fmt"
"github.com/aler9/goroslib"
)
// Creates a subscriber for the '/topic' topic, which just prints received messages.
type Sub struct {
Node *goroslib.Node
Subscriber *goroslib.Subscriber
}
func NewSub(name string) *Sub {
s := &Sub{}
var err error
s.Node, err = goroslib.NewNode(goroslib.NodeConf{
MasterHost: "localhost",
MasterPort: 11311,
Name: name,
})
if err != nil {
panic(err)
}
s.Subscriber, err = goroslib.NewSubscriber(goroslib.SubscriberConf{
Node: s.Node,
Topic: "/topic",
Callback: s.callback,
})
return s
}
func (s *Sub) callback(msg *Message) {
fmt.Printf("sub msg: %v\n", msg)
}
func (s *Sub) Close() {
if err := s.Subscriber.Close(); err != nil {
panic(err)
}
if err := s.Node.Close(); err != nil {
panic(err)
}
}
package main
import (
"github.com/aler9/goroslib/msg"
)
type Message struct {
msg.Package `ros:"ras"`
Msg string
}
The output is:
Using namespace ''
sub msg: &{0 Msg before sub}
sub msg: &{0 Msg after sub}
---
Using namespace 'namespace/'
sub msg: &{0 Msg before sub}
---
As you can see, the subscriber does indeed not receive updates from the publisher which was created after the subscriber.
The code can be found in the previous section.
I used ros noetic (1.15.8) in docker for testing:
docker run -it --network=host ros:noetic-ros-core roscore
Before making this issue, I did some digging, and I think I may have found the cause. When a new subscriber is created in node.go, it registers it with the master, and receives the existing publishers. This is why existing publishers do work:
// node.go:440
res, err := n.apiMasterClient.RegisterSubscriber(apimaster.RequestRegister{
Topic: req.sub.conf.Topic[1:],
TopicType: req.sub.msgType,
CallerUrl: n.apiSlaveServerUrl,
})
if err != nil {
req.err <- err
continue
}
n.subscribers[req.sub.conf.Topic] = req.sub
req.err <- nil
In the test the relevant values will be:
/namespace/sub
/topic
Subscribed to [/namespace/topic]
This is another confirmation that the master does the remapping.
Whenever a new publisher is created, node.go will handle the updating of urls. However, the topic check is done with the original topic, not with the remapped one. Since the ros master will send the remapped version, this check will fail, even though the publisher is in the same namespace as the subscriber:
//node.go:404
case req := <-n.publisherUpdate:
sub, ok := n.subscribers[req.topic]
if !ok {
continue
}
sub.publisherUpdate <- req.urls
In the test the relevant values will be:
/namespace/topic
{"/topic": [...]}
This shows the mismatch between the original and remapped topics.
A quick workaround for now is to put everything in the global namespace, although this is not a solution for bigger projects or projects with conflicting node names. I think a complete solution will have to be compliant with the ROS Names, so it might take some time to fully implement.
Something quick and dirty that could work for most cases would be something like this. In this solution you would just create a list of allowed namespaces, append the original topic name, and check for any match.
Hello,
does this library support time API as in Python?
For example, are there similar constructions to get time like rospy.get_time()
?
There is no problem with reality where we can use system time.
But simulation time is different from the latter, therefore I wonder how could we get it.
OS
Architecture
Prerequisite: update ros packages on PC A
to the latest versions via apt upgrade
.
A
] Start roscore
.A
] Run rostopic pub /test_topic std_msgs/String "data: 'hello world'"
.B
] Try to subscribe to /test_topic
topic with goroslib
.package main
import (
"fmt"
"github.com/aler9/goroslib"
"github.com/aler9/goroslib/pkg/msgs/std_msgs"
)
func onMessage(msg *std_msgs.String) {
fmt.Printf("Incoming: %+v\n", msg)
}
func main() {
// create a node and connect to the master
n, err := goroslib.NewNode(goroslib.NodeConf{
Name: "goroslib_sub",
MasterAddress: "PC-A:11311",
})
if err != nil {
panic(err)
}
defer n.Close()
// create a subscriber
sub, err := goroslib.NewSubscriber(goroslib.SubscriberConf{
Node: n,
Topic: "test_topic",
Callback: onMessage,
})
if err != nil {
panic(err)
}
defer sub.Close()
// freeze main loop
select {}
}
B
] Observe that the message callback was never called.Note:
A
is Ubuntu20.04
with ROS noetic
while PC B
is Ubuntu18.04
with ROS melodic
.B
while the goroslib app is on PC A
, the subscriber works as expected.apt-upgrade
since yesterday, I suspect some ros packages changes broke subscribers of goroslib
.Update: it works now again. I have really no idea what made it work :(
Hello , Do you have plan to support action servers ?
Thank you !
always missing th first message
pub:
Outgoing: &{Package:0 Header:{Package:0 Seq:0 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Outgoing: &{Package:0 Header:{Package:0 Seq:1 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Outgoing: &{Package:0 Header:{Package:0 Seq:2 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Outgoing: &{Package:0 Header:{Package:0 Seq:3 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Outgoing: &{Package:0 Header:{Package:0 Seq:4 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Outgoing: &{Package:0 Header:{Package:0 Seq:5 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
sub:
Incoming: &{Package:0 Header:{Package:0 Seq:1 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Incoming: &{Package:0 Header:{Package:0 Seq:2 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Incoming: &{Package:0 Header:{Package:0 Seq:3 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Incoming: &{Package:0 Header:{Package:0 Seq:4 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
Incoming: &{Package:0 Header:{Package:0 Seq:5 Stamp:0001-01-01 00:00:00 +0000 UTC FrameId:} Orientation:{Package:0 X:0 Y:0 Z:0 W:0} OrientationCovariance:[0 0 0 0 0 0 0 0 0] AngularVelocity:{Package:0 X:23.5 Y:22.1 Z:-7.5} AngularVelocityCovariance:[0 0 0 0 0 0 0 0 0] LinearAcceleration:{Package:0 X:0 Y:0 Z:0} LinearAccelerationCovariance:[0 0 0 0 0 0 0 0 0]}
OS
Architecture
simpleactionclient OnDone Wrong number of parameters because OnDone must accept 2 arguments
OS
Architecture
Description
I just updated, now the action clients are stuck in WaitForServer()
Originally posted by sniperZj August 24, 2021
code:
node, err := goroslib.NewNode(goroslib.NodeConf{
Name: "xx_node",
Host: "127.0.0.0.1",
MasterAddress: "127.0.0.0.1:11311",
})
if err != nil {
panic(err)
}
defer node.Close()
sac, err := goroslib.NewSimpleActionClient(goroslib.SimpleActionClientConf{
Node: node,
Name: "robot_pose_editor",
Action: &action.PoseEditAction{},
})
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": err.Error(),
"pose_id": 0,
})
return
}
defer sac.Close()
// wait for the server
fmt.Println("wait for the server")
sac.WaitForServer()
fmt.Println("create a simple action client end")
.........
failed to print properly "create a simple action client end"
rostopic echo robot_pose_editor/status
header:
seq: 4332
stamp:
secs: 1629807103
nsecs: 470941966
frame_id: ''
status_list: []
feedback、result、goal、cancel topic not data
Good afternoon.
First of all, thank you for your work and the fantastic library you have made available to the ROS community.
I was playing with the test files that you provide and I notice that it is not possible to see the frequency with which topics are published. I believe that's a bug.
Best regards,
Filipe Pinto
This does not prevent the system to work, but on rosnode info
on a goroslib
node, rosnode
has a xmlrpclib.ProtocolError
:
--------------------------------------------------------------------------------
Node [/goroslib]
Publications: None
Subscriptions:
* /test_pub [unknown type]
Services: None
contacting node http://192.168.1.65:44783 ...
Traceback (most recent call last):
File "/opt/ros/melodic/bin/rosnode", line 35, in <module>
rosnode.rosnodemain()
File "/opt/ros/melodic/lib/python2.7/dist-packages/rosnode/__init__.py", line 809, in rosnodemain
sys.exit(_rosnode_cmd_info(argv) or 0)
File "/opt/ros/melodic/lib/python2.7/dist-packages/rosnode/__init__.py", line 637, in _rosnode_cmd_info
rosnode_info(node, options.quiet)
File "/opt/ros/melodic/lib/python2.7/dist-packages/rosnode/__init__.py", line 595, in rosnode_info
print(get_node_connection_info_description(node_api, master))
File "/opt/ros/melodic/lib/python2.7/dist-packages/rosnode/__init__.py", line 531, in get_node_connection_info_description
pid = _succeed(node.getPid(ID))
File "/usr/lib/python2.7/xmlrpclib.py", line 1243, in __call__
return self.__send(self.__name, args)
File "/usr/lib/python2.7/xmlrpclib.py", line 1602, in __request
verbose=self.__verbose
File "/usr/lib/python2.7/xmlrpclib.py", line 1283, in request
return self.single_request(host, handler, request_body, verbose)
File "/usr/lib/python2.7/xmlrpclib.py", line 1331, in single_request
response.msg,
xmlrpclib.ProtocolError: <ProtocolError for 192.168.1.65:44783/RPC2: 400 Bad Request>
Steps to reproduce:
docker run --rm -it --network=host --name=roscore ros:melodic-ros-core-bionic roscore
docker run --rm -it --network=host golang:1.14 sh -c "git clone https://github.com/aler9/goroslib && cd goroslib && go run examples/subscriber.go"
docker run --rm -it --network=host --name=rosnode_info ros:melodic-ros-core-bionic rosnode info /goroslib
Hi, thanks for this package, it is extremely useful.
Is there a good reason to redefine the basic types in msgs
? I have an application that translates ROS messages to similar protobuf messages. I have to cast every value (for example msgs.Float64
to float64
). And for slices I need to copy all values to new slices of the correct type. This wouldn't be necessary if goroslib was using the basic types (like google.golang.org/protobuf
). Any chance you might agree to change it?
Hi @aler9 ,
Firstly, thank you for creating such a useful library. I would like to express some of the issues I am currently facing when using this library. Currently, I have a ROS environment (ROS Kinetic on Ubuntu 16.04) on my robot subscribing to a topic called '/cmd_vel'. On the server end, I have a Windows environment with Golang (Windows 10 Pro, Go 1.15.3), responsible for publishing the topic '/cmd_vel'.
I firstly did a roscore on the client side (robot), with the IP of 192.168.123.161 and port of 11311. I edited the following script such that this Golang script publishes 'geometry_msgs.Twist' message on the server side to the robot. Content published is displayed on the terminal. However on the client side, I can see the topic being published when i did rostopic list -v
, but when I performed a rostopic echo /cmd_vel
, it is an empty message. rostopic hz /cmd_vel
indicates that no new mesage is coming in, which implies that the initial 'handshake' is established but somehow messages are being dropped. Additionally, the published topic does not go away in rostopic echo /cmd_vel
even when I had stopped publishing from server side.
When I attempted to subscribe to another topic from server (Golang), there is no new message received as well. Here is the code I executed on Windows. Let me know if you have any insights to this issue, thanks!
func RosSending() {
// create a node with given name and linked to given master.
n, err := goroslib.NewNode(goroslib.NodeConf{
Name: "goroslib_pub",
MasterAddress: "192.168.123.161:11311",
})
if err != nil {
panic(err)
}
defer n.Close()
// create a publisher
pub, err := goroslib.NewPublisher(goroslib.PublisherConf{
Node: n,
Topic: "/cmd_vel",
Msg: &geometry_msgs.Twist{},
})
if err != nil {
panic(err)
}
defer pub.Close()
// publish a message every second
ticker := time.NewTicker(2 * time.Millisecond)
defer ticker.Stop()
for range ticker.C {
msg := &geometry_msgs.Twist{
Linear: geometry_msgs.Vector3{
X: x,
Y: y,
Z: z,
},
Angular: geometry_msgs.Vector3{
X: ax,
Y: ay,
Z: az,
},
}
fmt.Printf("Outgoing: %+v\n", msg)
pub.Write(msg)
}
}
Whne I startup a serviceclient, the client will exit with an error "no provider". That is different with "CPP".
What is your idea about this?Why do you call LookupService when NewServiceClient?
Followed the mini-tutorial in the README but I am sure I am missing something.
I have go 1.14 and ros kinetic installed, but I am unable to run any of the files for testing.
go run node file.go
is not a valid command for me (go run node) and when I run just go run file.go
I get a panic:
[signal SIGSEGV: segmentation violation code=0x1 addr=0x70 pc=0x689650]
goroutine 20 [running]:
github.com/aler9/goroslib.(*Publisher).Close(...)
/home/claudio/go/src/github.com/aler9/goroslib/publisher.go:403
github.com/aler9/goroslib.(*Node).run(0xc0000da3c0)
/home/claudio/go/src/github.com/aler9/goroslib/node.go:604 +0x1490
created by github.com/aler9/goroslib.NewNode
/home/claudio/go/src/github.com/aler9/goroslib/node.go:347 +0x793
exit status 2
I feel like there should be something to run between go mod init main
and go run node file.go
or something to download before. Or maybe I messed up something without even knowing. Any help would be appreciated!
I encountered cases when the ROS service misbehaved or network disrupted, the client just hung forever. I wonder if it's a good idea to add a new method ServiceClient.CallContext
or alike to allow timeout and cancellation on a per-call basis? Currently I wrap the call with context by myself, but since there's no timeout in this library, it could pile up a lot of coroutines.
Didn't read through the code, but I guess ReadServiceResState
https://github.com/aler9/goroslib/blob/main/pkg/prototcp/conn.go#L57 would be one place to retrofit. @aler9 if you generally agree, I probably can draft a PR sometime.
I have a topic in a bag where messages include an actionmsgs.GoalStatus
field. The subscriber doesn't deliver any message. It seems that the problem comes from the Definitions
in GoalStatus
.
Here's a simple way to reproduce the issue: in publisher-custom.go
and subscriber-custom.go
, add msgs.Definitions `ros:"uint8 A=0,uint8 B=1"`
in the definition of TestMessage
. Then the subscriber won't show any message.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.