|
Program with CarmenTODO: check types, function, etc
1 IntroductionThis document is designed to get CARMEN users started in writing new programs for integration into the program set. Because of the diverse skills and habits of programmers, the first section is a Style Guide to ensure compatability and clarity of new programs. The next secions describe the commands for getting information and issuing commands within CARMEN.
2 CARMEN Style Guide2.1 The Prime Directive You are not the only person who will ever have to read, understand and modify your code. 2.2 Units and Coordinates
2.3 Naming Conventions
2.4 Memory Management, System Calls, & Functions with Side Effects
2.5 IPC
2.6 Graphics
3 Getting Data from CarmenSensor data currently comes from one of two sources: the base module (such as scout, pioneer, etc.) provides raw odometry data and may provide sonar data, bumper data and infra-red (IR) data. The laser module may provide laser data. 3.0.1 Subscribing All of the following messages can be subscribed to by using helper functions in the appropriate xxx_interface library, e.g., base_interface. The helper functions are all of the form:
void carmen_robot_subscribe_xxxx_message(carmen_robot_xxx_message *msg, carmen_handler_t handler, carmen_subscribe_t subscribe_how); where carmen_handler_t and carmen_subscribe_t are defined as
typedef enum {CARMEN_UNSUBSCRIBE, CARMEN_SUBSCRIBE_LATEST, CARMEN_SUBSCRIBE_ALL} carmen_subscribe_t; typedef void (*carmen_handler_t)(void *); If the msg field of the subscribe function is NULL, then a static message is automatically allocated and returned as the argument to handler, otherwise the message pointer passed to the subscribe function is always used. In all cases, the same memory is re-used for all handled messages of the same message name, and passed as an argument to the handler function. If the handler field of the subscribe function is NULL, no handler is called, but the memory pointed to by msg is updated regularly. If both handler and msg are both NULL, your program will spend a fair chunk of time doing nothing useful for you. The subscribe_how field allows the user to either unsubscribe, or to start a new subscription. Subscribing only to the latest message allows the module to fall behind in processing messages without serious consequences. It should be pointed out that subscribing to all messages (CARMEN_SUBSCRIBE_ALL) does not guarantee all messages. Currently, the upper limit for the queue size is 1000 messages. If an IPC process actually subscribes to all messages and falls seriously behind (or wedges), central can run out of memory, or even worse, the TCP stack can overflow. Consequently, the Carmen subscription functions limit the maximum message queue size to 1000. A resourceful programmer can increase this queue (or even remove the queue size), but it is not clear this would ever be necessary. 3.0.2 Requesting Data Explicitly Some of these messages can also be obtained using explicit queries. To date, the only robot data that can be obtained using queries are from localize and navigator. Specifically, carmen_localize_globalpos_message, carmen_localize_particle_message, carmen_navigator_status_message and carmen_navigator_plan_message can all be obtained using specific query interface functions, which return the appropriate messages directly. These functions create new memory every time they return successfully; consequently, they should be used with care. 3.1 Sensor Data from the Base The timestamp field in all messages is defined to be the time when the data was first created or acquired (e.g, by scout or simulator). 3.1.1 Odometry
typedef struct { double timestamp; char *host; double x, y, theta; double tv, rv; double acceleration; } carmen_base_odometry_message; void carmen_base_subscribe_odometry_message(carmen_base_odometry_message *odometry, carmen_handler_t handler, carmen_subscribe_t subscribe_how); The x, y, theta fields are the raw odometry, from the time the robot was turned on. The tv and rv fields are the translational and rotational velocities of the robot. For robots that have differential drive (as opposed to synchrodrive), these velocities are computed from the left and right wheel velocities that base actual uses. 3.1.2 Sonar Sonar sensing is not properly supported by Carmen right now, and so subscribing to carmen_base_sonar_message messages may sometimes not work properly. But, if you care, it looks like:
typedef struct { double timestamp; char *host; int num_sonars; double sensor_angle; //width of sonar cone double *range; carmen_point_p positions; } carmen_base_sonar_message; typedef struct { double timestamp; char *host; int rate; int num_sonars; int *order; carmen_point_t *sonar_offsets; } carmen_base_sonar_conf_message; void carmen_base_subscribe_sonar_message(carmen_base_sonar_message *sonar, carmen_handler_t handler, carmen_subscribe_t subscribe_how); The sonar message reports a recent set of sonar range data from the base. There should be as many range points and offset points as described by num_sonars. The sonar_offsets describes the physical location and orientation of each transducer from the centre of the robot. There is currently no way to query the firing rate or order of the sonar transducers, and the sonar_conf message is not yet supported. (Or even defined by any module.) 3.1.3 Bumper and IR sensors
typedef struct { double timestamp; char *host; int num_bumpers; unsigned char *state; } carmen_base_bumper_message; typedef struct { double timestamp; char *host; int num_irs; double *range; } carmen_base_ir_message; typedef struct { double timestamp; char *host; int history; int num_irs; int order[32]; } carmen_base_ir_conf_message; These messages will probably change, and are not yet supported. 3.1.4 Laser data Laser data is defined as a set of ranges, of number given by the num_readings field, contained in range. It furthermore provides remission values (if available) using num_remissions and the field remission. The order of the values is right-handed (counter-clockwise). The configuration of the laser is privided by
typedef struct { /* what kind of laser is this */ carmen_laser_laser_type_t laser_type; /* angle of the first beam relative to to the center of the laser */ double start_angle; /* field of view of the laser */ double fov; /* angular resolution of the laser */ double angular_resolution; /* the maximum valid range of a measurement */ double maximum_range; /* error in the range measurements*/ double accuracy; /* if and what kind of remission values are used */ carmen_laser_remission_type_t remission_mode; } carmen_laser_laser_config_t; All these values are given relative to the heading of the laser.
The timestamp field in all messages is defined to be the time when the data was first created or acquired (e.g, by laser or simulator), not the timestamp of some intermediate process (such as the correction applied by robot when applying odometry interpolation and correction). Similarly, the hostfield is defined to be the hostname associated with the origin of the data, not the hostname of some intermediary converting the data from raw form to interpolated form.
typedef struct { double timestamp; char *host; carmen_laser_laser_config_t config; int num_readings; float *range; int num_remissions; float *remission; } carmen_laser_laser_message; typedef enum {SICK_LMS, SICK_PLS, HOKUYO_URG, SIMULATED_LASER, UMKNOWN_PROXIMITY_SENSOR} carmen_laser_laser_type_t; typedef enum {OFF, DIRECT, NORMALIZED} carmen_laser_remission_type_t;Carmen currently supports up to 4 laser range finder. The subscribe message are given by: void carmen_laser_subscribe_laser1_message(carmen_laser_laser_message *laser, carmen_handler_t handler, carmen_subscribe_t subscribe_how); void carmen_laser_subscribe_laser2_message(carmen_laser_laser_message *laser, carmen_handler_t handler, carmen_subscribe_t subscribe_how); void carmen_laser_subscribe_laser3_message(carmen_laser_laser_message *laser, carmen_handler_t handler, carmen_subscribe_t subscribe_how); void carmen_laser_subscribe_laser4_message(carmen_laser_laser_message *laser, carmen_handler_t handler, carmen_subscribe_t subscribe_how); void carmen_laser_subscribe_alive_message(carmen_laser_alive_message *alive, carmen_handler_t handler, carmen_subscribe_t subscribe_how); This message is defined by laser and by simulator, and the same message struct is used by both carmen_laser_frontlaser and carmen_laser_rearlaser messages. As a consequence, there is no way to tell from a message itself whether or not the message is a front laser message or a rear laser message. This might be fixed in a future release. 3.1.5 Robot messages These messages are defined and emitted by robot.
3.2 Map-based Navigation Messages 3.2.1 Localize Messages
3.2.2 Autonomous Navigation
4 Commanding the RobotWhile it is (obviously) possible to send messages directly to the base module, this is not an exposed interface. Sending velocities directly to the base side-steps the last-mile collision avoidance module, and can also result in all kinds of pathologies as modules fight for control of the robot. 4.1 Moving the Robot
4.2 Initializing Localize
carmen_localize_initialize_messageThis message provides a way to initialize localization.
typedef struct { double timestamp; char *host; int distribution; int num_modes; carmen_point_t *mean, *std; } carmen_localize_initialize_message; The distribution specifies the kind of distribution to use for initialization. At the moment only one type of distribution is supported: CARMEN_INITIALIZE_GAUSSIAN. (The localize_messages.h file also lists a CARMEN_INITIALIZE_UNIFORM distribution type, but this is not currently supported by localize itself.) The 3-dimensional point mean specifies the x, y, q mean of the gaussian, and std specified the sx, sy, sq standard deviations of the gaussian. Reasonable values for the standard deviations are (0.2m, 0.2m, 4.0°). It is also possible to initialize localize through the navigator by using the carmen_navigator_set_robot or carmen_navigator_set_robot_map messages, but these messages are deprecated. 4.2.1 Setting A Goal This message provides a way to set the goal or destination for navigation. It is not possible (nor should it ever be possible) to set multiple goals inside the navigator.
typedef struct { double timestamp; char *host; double x, y; } carmen_navigator_set_goal_message; int carmen_navigator_set_goal(double x, double y); typedef struct { double timestamp; char *host; char *placename; } carmen_navigator_placename_message; int carmen_navigator_set_goal_place(char *name); The (x, y) fields should be self-explanatory as the goal position, in the global reference frame (see the Carmen Style Guide), as always in metres. If the map contains place names, then it is also possible to set the goal position using a carmen_navigator_placename_message, and the carmen_navigator_set_goal_place helper function. This has no effect if the map does not contain a place name that matches. 4.3 Autonomous Motion These messages toggle the navigator in and out of autonomous motion.
typedef carmen_default_message carmen_navigator_stop_message; typedef carmen_default_message carmen_navigator_go_message; int carmen_navigator_stop(void); int carmen_navigator_go(void); If the robot is already at the current goal position, then the carmen_navigator_go_command will cause the navigator to change momentarily into autonomous mode, and then switch back again, emitting a carmen_navigator_autonomous_stopped_message with CARMEN_NAVIGATOR_GOAL_REACHED_v as the reason. When the navigator receives a carmen_navigator_stop_message, then a carmen_navigator_autonomous_stopped_message is emitted with CARMEN_NAVIGATOR_USER_STOPPED_v as the reason.
5 Getting Maps5.1 Grid Maps
typedef carmen_default_message carmen_gridmap_request_message; int carmen_map_get_gridmap(carmen_map_p map); 5.2 Map Placelists
typedef struct { double timestamp; char *host; carmen_place_p places; int num_places; } carmen_map_placelist_message; int carmen_map_get_placelist(carmen_map_placelist_p placelist); 5.3 Off Limits Regions
typedef struct { double timestamp; char *host; carmen_offlimits_p offlimits_list; int list_length; } carmen_map_offlimits_message; int carmen_map_get_offlimits(carmen_offlimits_p *offlimits, int *list_length); 5.4 Navigator Maps
typedef struct { double timestamp; char *host; unsigned char *data; int size; int compressed; carmen_map_config_t config; carmen_navigator_map_t map_type; } carmen_navigator_map_message; int carmen_navigator_get_map(carmen_navigator_map_t map_type, carmen_navigator_map_message **map_pointer);
6 Getting Parameters [THIS SECTION NEEDS AN UPDATE]Parameters can be acquired from the parameter server using functions in libparam_interface, eg:
int carmen_param_get_int(char *variable, int *return_value); int carmen_param_get_double(char *variable, double *return_value); int carmen_param_get_onoff(char *variable, int *return_value); int carmen_param_get_string(char *variable, char **return_value); The conversion of parameters to ints, doubles, etc. is done on demanded by the interface library. If you do not wish the library to convert the parameter to the appropriate type, simply request the parameter as a string. If there is no definition for the parameter requested, then the library will output a warning to the terminal, unless this warning has been turned off using carmen_param_allow_unfound_variables(1);. Also, as a convience, variables can be requested either by specifying the fully qualified module_param-name name, or by first specifying a module using carmen_param_set_module(char *), and the specifying just the param-name form. 6.1 Subscribing to Changes Some processes may wish to subscribe to changes to parameters during their execution, for example changing the robot speed or acceleration profile, or changing the robotgraph display parameters. Of course, some processes should not suscribe to some parameter changes: changing the number of particles localize uses during execution would result in disaster. Parameter changes can be subscribed using the functions below: void carmen_param_subscribe_int(char *module, char *variable, int *variable_address, carmen_param_change_handler_t handler); void carmen_param_subscribe_double(char *module, char *variable, double *variable_address, carmen_param_change_handler_t handler); void carmen_param_subscribe_onoff(char *module, char *variable, int *variable_address, carmen_param_change_handler_t handler); void carmen_param_subscribe_string(char *module, char *variable, char **variable_address, carmen_param_change_handler_t handler); These functions take a module and variable name as parameters. The subscription mechanism can either silently change variable values as parameters change, or can invoke a callback when a parameter is changed. If the variable_address parameter is non-NULL, then the new parameter value is stored at this address (in the case of strings, this is a pointer to some newly-malloc'd memory containing the new string definition. If the variable address is non-NULL when the parameter changes, the old memory is freed.) If the handler parameter is non-NULL, then function pointed to by handler is invoked whenever the parameter changes. If both are non-NULL, then the variable changes and then the callback invoked. If both are NULL, then the subscription mechanism does not do much. 6.2 The Parameter Factory Parameters can be loaded in a single step using the parameter factory methods, much like the gtk menu item factory methods. The set of parameters to be loaded should be described in an array of carmen_param_t, and passed to void carmen_param_install_params(int argc, char *argv[], carmen_param_p param_list, int num_items); Each parameter in the array of type carmen_param_t has the form: typedef struct { char *module; char *variable; carmen_param_type_t type; void *user_variable; int subscribe; carmen_param_change_handler_t handler; } carmen_param_t;where module is the module name, variable is the variable name, type is one of CARMEN_PARAM_INT, CARMEN_PARAM_DOUBLE, CARMEN_PARAM_ONOFF or CARMEN_PARAM_STRING. The parameter is loaded into user_variable, whose original type should match that specified in the type field. If subscribe is set to 1, then the process will subscribe to changes to the parameter, and set up a callback on the function specified in handler (if not NULL). The callback parameter is ignored if subscribe is set to 0, and the parameter is only loaded once. There is no way to use the parameter factory methods, subscribe to a variable and not have the variable's value updated automatically. If carmen_param_allow_unfound_variables() is set to 0 (by default), then carmen_param_install_params will exit with an error on the first parameter absent from the parameter server, reporting what the problematic parameter is. If a process loads its parameter set using the parameter factory methods, then running the process with the -h or -help command line option will print out a list of parameters used by that process, their expected types and whether or not the process subscribes to changes. 6.3 Specifying Parameters from the Command Line Parameter values can be temporarily over-ridden from the command line of a given process, for that process only. For example: % robot -max_t_vel 0.1will specify a max_t_vel of 0.1 m/s for the robot process only. This parameter specification method is not advised, is a convenience only, and may be removed from future versions of carmen. Command-line parameters are assumed to have no module name, and attempts are made to find a parameter with any module name and matching parameter name. If a process uses multiple parameters with different module names and the same parameter name, the behaviour of command-line specification is undefined.
| |||
Copyright © by the CARMEN-Team |