I am writing a program that is supposed to remotely run ROS2 launch files on a connected robot via SSH. I am using Golang to connect to the robot via SSH and run ROS2 commands. So far this setup has worked, I have been able to run ROS2 commands such as
ros2 topic list
and ros2 topic info
, and they have returned the expected output. When I try to run a ros2 launch file however, no output is returned, and running commands on the robot to try and detect if the node is running (ros2 node list
) show that the launched nodes are not running.
My code for executing SSH commands via go is:
func (serverMsg *BaseWSServerMsg) executeArbitrarySSH(payload interface{}, c *websocket.Conn) {
type arbSSH struct {
Data string `json:"data,omitempty"`
Port int `json:"port,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Hostname string `json:"hostname,omitempty"`
Type string `json:"type,omitempty"`
}
marshalled, err := json.Marshal(payload)
if err != nil {
serverMsg.CreateAsError(http.StatusBadRequest, err.Error())
return
}
//load, ok := payload.(arbSSH)
var load arbSSH
err = json.Unmarshal(marshalled, &load)
if err != nil {
serverMsg.CreateAsError(http.StatusBadRequest, fmt.Sprintf(err.Error()))
return
}
config := &ssh.ClientConfig{
User: load.Username,
Auth: []ssh.AuthMethod{
ssh.Password(load.Password),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", load.Hostname, load.Port), config)
if err != nil {
serverMsg.CreateAsError(http.StatusInternalServerError, err.Error())
return
}
// Each ClientConn can support multiple interactive sessions,
session, err := client.NewSession()
if err != nil {
serverMsg.CreateAsError(http.StatusInternalServerError, err.Error())
return
}
if load.Type == "output" {
fmt.Println("Recieved Output command")
defer client.Close()
defer session.Close()
stdout, err := session.Output(load.Data)
if err != nil {
serverMsg.CreateAsError(http.StatusInternalServerError, err.Error())
return
}
serverMsg.Payload = struct {
Data string `json:"data,omitempty"`
}{string(stdout)}
}
}
This implementation of go ssh creates a new ssh terminal for each command run, so prior to running each command I source the needed files and create the required environment variables to ensure that ros runs correctly. To demonstrate this format, an example command I might run looks like:
export ROS_DOMAIN_ID=30 > /dev/null && source /opt/ros/humble/setup.bash > /dev/null && source ~/example_ws/install/local_setup.bash > /dev/null && ros2 launch example example.launch.py
This format has worked for all other ros commands I have tried so far as I mentioned above. I retested the exact launch commands I sent via go in a regular SSH terminal connected to my robot and they work just fine, launching the expected nodes and displaying output.
I have tried adding ‘&’ to the end of the command to make it run in the background, but that did not make it run correctly. I attempted using ‘nohup’ to run the command, however that also changed nothing.
I have done further testing on running launch files through ssh to try and see if the problem stems from interactivity. I discovered that when running the command directly from ssh instead of using an interactive ssh terminal, as follows:
ssh username@ip_address "export ROS_DOMAIN_ID=30 > /dev/null && source /opt/ros/humble/setup.bash > /dev/null && source ~/example_ws/install/local_setup.bash > /dev/null && ros2 launch example example.launch.py"
I discovered that the command would run, displaying the correct ROS_INFO output on my ssh terminal, however when trying to check if that node was running on the robot, by running ros2 node list
and ros2 topic list
no corresponding node would be displayed. The ROS_DOMAIN_ID is the same on both the robot and the ssh terminal command. I am wondering if this behaviour might be connected to the problem I am facing, and if so how do I bypass it?
user25009967 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.