Skip to content
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

getParam (and getParams) not returning anything #129

Open
guru-florida opened this issue Jan 6, 2020 · 4 comments
Open

getParam (and getParams) not returning anything #129

guru-florida opened this issue Jan 6, 2020 · 4 comments

Comments

@guru-florida
Copy link

Using Ros2 Web Bridge on ROS2 Eloquent:

I am calling getParam with a valid node name but not getting param data back. The callback is not executed. I do get plenty of subscription callbacks so the websocket and communication to ros2 web bridge is working fine. Inspecting the network tab details, I see that the request is properly going out but the web bridge is replying back with a non-descript error. You can see in this screenshot a bunch of /compliance/params subscription events (great!) but the service call to rosapi/get_param is failing with set_level "error":
image

I enabled debug stats in the ros2 bridge using:
DEBUG=ros2-web-bridge:Bridge node bin/rosbridge.js
...and I get this related error:

ros2-web-bridge:Bridge JSON command received: {"op":"call_service","id":"call_service:/rosapi/get_param:44","service":"/rosapi/get_param","type":"rosapi/GetParam","args":{"name":"/imu"}} +71ms
  ros2-web-bridge:Bridge Exception caught in Bridge.executeCommand(): Error: The message required does not exist: rosapi, srv, GetParam +1ms
  ros2-web-bridge:Bridge Error: Error: The message required does not exist: rosapi, srv, GetParam happened when executing command call_service +0ms
  ros2-web-bridge:Bridge Response: {"op":"set_level","id":"call_service:/rosapi/get_param:44","level":"error"} +0ms

It suggests the rosapi.srv.GetParam message doesnt exist. I took a gander around the rclnodejs generated directory and I indeed can't find the message. Seems like the relevant service messages would be in generated/rcl_interfaces, yes? I see in that folder a bunch of param server and request/result messages. Grep'ing for msgname within all those generated files I get:

$ find node_modules/rclnodejs/generated/rcl_interfaces -exec  grep "msgName\": " {} \;
  "msgName": "SetParametersAtomically_Request"
  "msgName": "GetParameterTypes_Response"
  "msgName": "ParameterValue"
  "msgName": "GetParameters_Response"
  "msgName": "GetParameters_Request"
  "msgName": "ListParametersResult"
  "msgName": "Log"
  "msgName": "ParameterEventDescriptors"
  "msgName": "FloatingPointRange"
  "msgName": "SetParametersResult"
  "msgName": "IntegerRange"
  "msgName": "ListParameters_Response"
  "msgName": "ParameterType"
  "msgName": "ListParameters_Request"
  "msgName": "GetParameterTypes_Request"
  "msgName": "SetParametersAtomically_Response"
  "msgName": "Parameter"
  "msgName": "IntraProcessMessage"
  "msgName": "SetParameters_Response"
  "msgName": "SetParameters_Request"
  "msgName": "ParameterEvent"
  "msgName": "DescribeParameters_Request"
  "msgName": "DescribeParameters_Response"
  "msgName": "ParameterDescriptor"

Did Eloquent perhaps change the Param service messages? Any other advice/suggestions?

Thank you,
Colin

@minggangw
Copy link
Member

Thanks for reporting this problem. The rosapi is not supported by this ROS2 bridge currently, please also see #73

@guru-florida
Copy link
Author

Ok, I figured out that the ros2 bridge is trying to send the param get/set request to a rosapi node that is part of ros2-web-suite. I tried getting that working and got it running but doesnt work. However, in the process learned a thing or two about managing ROS2 parameters via the get/set_parameter service calls on each node. The ros2-web-bridge has no problem calling services so I would say this is the preferred way to manage parameters in ROS2 and no rosapi node needed!

I wrote some code. I could add to Ros class and do a PR if you like. I did parameter getter/setters but didnt do param enumeration yet.

export enum ParameterType {
    NOT_SET=0,
    BOOL=1,
    INTEGER=2,
    DOUBLE=3,
    STRING=4,
    BYTE_ARRAY=5,
    BOOL_ARRAY=6,
    INTEGER_ARRAY=7,
    DOUBLE_ARRAY=8,
    STRING_ARRAY=9,
}

export interface Parameter {
    node: string;
    name: string;
    typeid: ParameterType;
    value: any;
}

interface ServiceParameterValue {
    type: number;

    //  "Variant" style storage of the parameter value.
    bool_value?: boolean;
    integer_value?: number;
    double_value?: number;
    string_value?: string;
    byte_array_value?: number[];
    bool_array_value?: boolean[];
    iinteger_array_value?: number[];
    double_array_value?: number[];
    string_array_value?: string[];
}

interface ServiceParameter {
    name: string;
    value: ServiceParameterValue;
}

interface ServiceParameterResult {
    successful: boolean;
    reason: string;
}

export class GetParameterRequest {
    ros: ROS.Ros;
    node: string;
    name: string | string[];
}

export class SetParameterRequest {
    ros: ROS.Ros;
    node: string;
    params: ServiceParameter | [ServiceParameter];
}


function pull_parameter(p: ServiceParameterValue) {
    switch(p.type) {
        case ParameterType.NOT_SET: return null;
        case ParameterType.BOOL: return p.bool_value;
        case ParameterType.INTEGER: return p.integer_value;
        case ParameterType.DOUBLE: return p.double_value;
        case ParameterType.STRING: return p.string_value;
        case ParameterType.BYTE_ARRAY: return p.byte_array_value;
        case ParameterType.BOOL_ARRAY: return p.bool_array_value;
        case ParameterType.INTEGER_ARRAY: return p.iinteger_array_value;
        case ParameterType.DOUBLE_ARRAY: return p.double_array_value;
        case ParameterType.STRING_ARRAY: return p.string_array_value;
        default:
            console.warn("no way to determine value from Parameter ", p);
            break;
    }
}

/* Get/Set METHODS
 * I had these as part of a class, they could be added to the ROSLIB.Ros class.
 */
    public getParameters(request: GetParameterRequest) {
        let svc = new ROS.Service({
            ros: request.ros,
            name: request.node+'/get_parameters',
            serviceType: 'rcl_interfaces/srv/GetParameters'
        });

        const param_names = Array.isArray(request.name)
            ? request.name
            : [ request.name ];
        let svc_request = new ROS.ServiceRequest({
            names: param_names
        });

        return new Promise<Parameter[]>( (resolve,  reject) => {
            svc.callService(svc_request, response => {
                if(Array.isArray(response.values)) {
                    // convert parameters to javascript friendly
                    resolve( response.values.map( (v: ServiceParameterValue, idx: number) => ({
                        node: request.node,
                        name: param_names[idx],
                        typeid: v.type,
                        value: pull_parameter(v)
                    } as Parameter)));
                }
            }, reject);
        });
    }

    public setParameters(request: SetParameterRequest) {
        let svc = new ROS.Service({
            ros: request.ros,
            name: request.node+'/set_parameters',
            serviceType: 'rcl_interfaces/srv/SetParameters'
        });

        const params = Array.isArray(request.params)
            ? request.params
            : [ request.params ];
        let svc_request = new ROS.ServiceRequest({
            parameters: params
        });

        return new Promise<ServiceParameterResult[]>( (resolve,  reject) => {
            svc.callService(svc_request, response => {
                if(Array.isArray(response.results)) {
                    // convert parameters to javascript friendly
                    resolve( response.results as ServiceParameterResult[] );
                }
            }, reject);
        });
    }

`

@minggangw
Copy link
Member

Absolutely, please submit your PR, thanks!

@guru-florida
Copy link
Author

Sounds good. I got param enumeration too. I will fork and integrate changes and take a week to test in my own system before submitting the PR. So give me a week's time. Thanks!

I will also be doing service calls for Node Lifecycle management so I may follow up with a second PR on that one as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants