Skip to content

Commit

Permalink
Merge branch 'master' into webots-controller-matlab-macos
Browse files Browse the repository at this point in the history
  • Loading branch information
omichel authored Sep 25, 2023
2 parents 0ccb3b8 + 0e1ab73 commit 7e41398
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 59 deletions.
53 changes: 25 additions & 28 deletions docs/guide/matlab.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ Here is a simple MATLAB controller example:
```MATLAB
function simple_example
% uncomment the next two lines to use the MATLAB desktop
%desktop;
%keyboard;
TIME_STEP = 32;
my_led = wb_robot_get_device('my_led');
Expand All @@ -40,41 +36,42 @@ while wb_robot_step(TIME_STEP) ~= -1
end
```

### Using the MATLAB Desktop
### Debugging Using the MATLAB Desktop

In order to avoid cluttering the desktop with too many windows, Webots starts MATLAB with the *-nodesktop* option.
The *-nodesktop* option starts MATLAB without user interface and therefore it keeps the memory usage low which is useful in particular for multi-robot experiments.
If you would like to use the MATLAB desktop to interact with your controller you just need to add these two MATLAB commands somewhere at the beginning of your controller m-file:
For each controller written using MATLAB, Webots will start a new instance of MATLAB to act as an interpreter.
In order to avoid cluttering the desktop with too many windows, Webots starts each instance of MATLAB in non-interactive mode.
This means that MATLAB starts without the user interface which keeps the memory usage low; this is particularly useful in multi-robot experiments.
Any output to stdout (such as `disp` or `fprintf`) will also be redirected to the Webots console.

```MATLAB
desktop;
keyboard;
```
If you would like to use the MATLAB desktop to interact with your controller, you will need to run it in `<extern>` mode with the appropriate additional argument.
You can read more about that [here](running-extern-robot-controllers.md).

The `desktop` command brings up the MATLAB desktop.
The `keyboard` stops the execution of the controller and gives control to the keyboard (`K>>` prompt).
Then MATLAB opens your controller m-file in its editor and indicates that the execution is stopped at the `keyboard` command.
After that, the controller m-file can be debugged interactively, i.e., it is possible to continue the execution step-by-step, set break points, watch variable, etc.
While debugging, the current values of the controller variables are shown in the MATLAB workspace.
It is possible to *continue* the execution of the controller by typing `return` at the `K>>` prompt.
Finally the execution of the controller can be terminated with <kbd>ctrl</kbd>-<kbd>C</kbd> key combination.
**Note**: This is equivalent to inserting the command `keyboard` in your controller code, but this is strongly discouraged since it will cause an error during non-interactive execution of the code.

Once the controller is terminated, the connection with Webots remains active.
Running an external controller in interactive mode will automatically place a breakpoint at the first line of your controller.
Once MATLAB desktop has initialized, it will halt the execution of the controller and give control to the keyboard (`K>>` prompt).
MATLAB also opens your controller m-file in its editor and indicates that the execution is stopped at the breakpoint.

At this point, the controller m-file can be debugged interactively, i.e., it is possible to continue the execution step-by-step, set break points, watch variable, etc.
You can use the navigation buttons in the Editor Toolstrip such as Continue/Pause, Step, and Quit Debugging to control the execution.
While running, the controller will run normally until it terminates or reaches another breakpoint.
While paused, the current values of the controller variables are shown in the MATLAB workspace, and the Command Window becomes available.
You can read more about debugging MATLAB code on the [MathWorks homepage](https://www.mathworks.com/help/matlab/matlab_prog/debugging-process-and-features.html).

While paused (or after the controller has been terminated), the connection with Webots remains active.
Therefore it becomes possible to issue Webots commands directly on the MATLAB prompt, for example you can interactively issue commands to query the sensors, etc.:

```MATLAB
>> wb_robot_step(1000);
>> wb_gps_get_values(gps)
K>> wb_robot_step(1000);
K>> wb_gps_get_values(gps)
ans =
0.0001 0.0030 -0.6425
>> |
```

It is possible to use additional `keyboard` statements in various places in your ".m" controller.
So each time MATLAB will run into a `keyboard` statement, it will return control to the `K>>` prompt where you will be able to debug interactively.

At this point, it is also possible to restart the controller by calling its m-file from MATLAB prompt.
The execution of the controller can be terminated with <kbd>Ctrl</kbd>+<kbd>C</kbd> key combination, or by quitting the debugger.
However, since all controllers are functions, their Workspace (local variables) will be lost after termination.
It is possible to re-run the controller by calling `launcher` from MATLAB prompt.
Note that this will restart the controller only, not the whole simulation, so the current robot and motor positions will be preserved.
If you want to restart the whole simulation you need to use the `Reload` button as usual.
If you want to restart the whole simulation you need to use the `Reload` button in Webots as usual.
10 changes: 9 additions & 1 deletion docs/guide/running-extern-robot-controllers.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ Concrete use cases are discussed in the [Setup](#setup) section.
--robot-name=<robot-name>
Target a specific robot by specifying its name in case multiple robots wait for an extern controller in the Webots instance.
--interactive
Launch MATLAB in interactive debugging mode.
See https://cyberbotics.com/doc/guide/matlab#using-the-matlab-desktop for more information.
--matlab-path=<matlab-path>
For MATLAB controllers, this option allows to specify the path to the executable of a specific MATLAB version.
By default, the launcher checks in the default MATLAB installation folder.
Expand Down Expand Up @@ -170,7 +174,11 @@ It is recommended that you do not override this `WEBOTS_TMPDIR` environment vari
### Running a MATLAB Extern Robot Controller

Matlab controllers can also be started using the launcher.
By default, the launcher will look for the latest installed version of MATLAB in the following locations, depending on the OS:
By default, the new instance of MATLAB will be running in non-interactive ("batch") mode.
However, by providing the `--interactive` option, this can be overridden, which will cause the full desktop user interface to run.
See [this page](matlab.md) for more details on how to debug webots controllers using the MATLAB desktop.

Regardless of mode, the launcher will look for the latest installed version of MATLAB in the following locations, depending on the OS:

- **Windows**: C:\Program Files\MATLAB\R20XXx\bin\win64\MATLAB.exe
- **Linux**: /usr/local/MATLAB/R20XXx/bin/matlab
Expand Down
1 change: 1 addition & 0 deletions docs/reference/changelog-r2023.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Released on XXX XXth, 2023.
- New Devices and Objects
- Added a model of a silo and a field ditch ([#6289](https://github.com/cyberbotics/webots/pull/6289)).
- Enhancements
- Enabled the launching of MATLAB desktop from the extern launcher ([#6366](https://github.com/cyberbotics/webots/pull/6366)).
- Improved overlays visible in Overlays menu by adding all the robots in the menu list ([#6297](https://github.com/cyberbotics/webots/pull/6297)).
- Bug fixes
- Fixed errors loading template PROTO if the system user name, the project path, or the temporary directory path contains the `\` character ([#6288](https://github.com/cyberbotics/webots/pull/6288)).
Expand Down
2 changes: 2 additions & 0 deletions lib/controller/matlab/launcher.m
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,11 @@
if ~isvarname(WEBOTS_CONTROLLER_NAME)
newname = matlab.lang.makeValidName(WEBOTS_CONTROLLER_NAME);
copyfile(append(WEBOTS_CONTROLLER_NAME, '.m'), append(newname, '.m'), 'f');
if desktop('-inuse'), dbstop('in', newname); end
eval([newname, args]);
delete(append(newname, '.m')); % delete temporary file
else
if desktop('-inuse'), dbstop('in', WEBOTS_CONTROLLER_NAME); end
eval([WEBOTS_CONTROLLER_NAME, args]);
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
% Description: MATLAB controller example for Webots
function symmetry_matlab

% uncomment the next two lines if you want to use
% MATLAB's desktop and interact with the controller
%desktop;
%keyboard;

TIME_STEP = wb_robot_get_basic_time_step();

right_shoulder_motor = wb_robot_get_device('ShoulderR');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
% -MATLAB must be installed and the "matlab" command must be in the PATH environment variable
function supervisor_matlab

% uncomment the next two lines if you want to use
% MATLAB's desktop to interact with this controller:
%desktop;
%keyboard;

% controller time step
TIME_STEP = 40;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
%
% Example of spring and dampers simulation implemented with force control
% To try this example you need to change the Robot.controller field
% to "force_control_matlab" in the force_control.wbt example
%
function force_control_matlab

% uncomment the next two lines if you want to use
% MATLAB's desktop to interact with the controller:
%desktop;
%keyboard;
function force_control_matlab

CONTROL_STEP = 4;
SPRING_CONSTANT = 40;
Expand Down
46 changes: 33 additions & 13 deletions src/controller/launcher/webots_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static char *controller;
static char *controller_path;
static char *controller_extension;
static char *matlab_path;
static char *matlab_args;
static char *current_path;
static int nb_controller_arguments;
static int next_argument_index;
Expand Down Expand Up @@ -185,7 +186,7 @@ static bool get_matlab_path() {
DIR *directory = opendir(matlab_directory);
#ifndef __APPLE__
if (directory == NULL) {
fprintf(stderr, "No installation of Matlab available.\n");
fprintf(stderr, "No installation of MATLAB available.\n");
return false;
}
#endif
Expand All @@ -203,7 +204,7 @@ static bool get_matlab_path() {
}
closedir(directory);
if (!latest_version) {
fprintf(stderr, "No installation of Matlab available.\n");
fprintf(stderr, "No installation of MATLAB available.\n");
return false;
}

Expand Down Expand Up @@ -233,11 +234,12 @@ static void print_options() {
"connect.\n 1234 is used by default, as it is the default port for Webots.\n This setting allows you to connect to a "
"specific instance of Webots if\n there are multiple instances running on the target machine.\n The port of a Webots "
"instance can be set at its launch.\n\n --robot-name=<robot-name>\n Target a specific robot by specifying its name in "
"case multiple robots wait\n for an extern controller in the Webots instance.\n\n --matlab-path=<matlab-path>\n For "
"MATLAB controllers, this option allows to specify the path to the\n executable of a specific MATLAB version.\n By "
"default, the launcher checks in the default MATLAB installation folder.\n See "
"https://cyberbotics.com/doc/guide/running-extern-robot-controllers#running-a-matlab-extern-controller\n for more "
"information.\n\n --stdout-redirect\n Redirect the stdout of the controller to the Webots console.\n\n "
"case multiple robots wait\n for an extern controller in the Webots instance.\n\n --interactive\n Launch MATLAB "
"in interactive debugging mode.\n See https://cyberbotics.com/doc/guide/matlab#using-the-matlab-desktop for\n more "
"information.\n\n --matlab-path=<matlab-path>\n For MATLAB controllers, this option allows to specify the path to the "
"\n executable of a specific MATLAB version.\n By default, the launcher checks in the default MATLAB installation "
"folder.\n See https://cyberbotics.com/doc/guide/running-extern-robot-controllers#running-a-matlab-extern-controller\n"
" for more information.\n\n --stdout-redirect\n Redirect the stdout of the controller to the Webots console.\n\n "
"--stderr-redirect\n Redirect the stderr of the controller to the Webots console.\n\n");
}

Expand All @@ -250,6 +252,7 @@ static bool parse_options(int nb_arguments, char **arguments) {

controller = NULL;
matlab_path = NULL;
matlab_args = NULL;
char *protocol = NULL;
char *ip_address = NULL;
char *port = NULL;
Expand All @@ -273,6 +276,14 @@ static bool parse_options(int nb_arguments, char **arguments) {
const size_t robot_name_size = strlen(arguments[i] + 13) + 1;
robot_name = malloc(robot_name_size);
memcpy(robot_name, arguments[i] + 13, robot_name_size);
} else if (strncmp(arguments[i], "--interactive", 13) == 0) {
#ifdef _WIN32
matlab_args = malloc(strlen("-wait -r") + 1);
sprintf(matlab_args, "-wait -r");
#else
matlab_args = malloc(strlen("-r") + 1);
sprintf(matlab_args, "-r");
#endif
} else if (strncmp(arguments[i], "--matlab-path=", 14) == 0) {
const size_t matlab_path_size = strlen(arguments[i] + 14) + 1;
matlab_path = malloc(matlab_path_size);
Expand Down Expand Up @@ -344,11 +355,12 @@ static bool parse_options(int nb_arguments, char **arguments) {

// Show resulting target options to user
const char *location = strncmp(protocol, "tcp", 3) == 0 ? "remote" : "local";
printf("The started controller targets a %s instance (%s protocol) of Webots with port number %s.", location, protocol, port);
strncmp(protocol, "tcp", 3) == 0 ? printf(" The IP address of the remote Webots instance is '%s'. ", ip_address) :
printf(" ");
robot_name ? printf("Targeting robot '%s'.\n\n", robot_name) :
printf("Targeting the only robot waiting for an extern controller.\n\n");
printf("\nThe started controller targets a %s instance (%s protocol) of Webots with port number %s.", location, protocol,
port);
strncmp(protocol, "tcp", 3) == 0 ? printf(" The IP address of the remote Webots instance is '%s'.\n", ip_address) :
printf("\n");
robot_name ? printf("Targeting robot '%s'.\n", robot_name) :
printf("Targeting the only robot waiting for an extern controller.\n");

free(protocol);
free(ip_address);
Expand Down Expand Up @@ -723,6 +735,7 @@ static char **add_controller_arguments(char **argv, char **controller_argv, size
static void free_memory() {
free(WEBOTS_HOME);
free(matlab_path);
free(matlab_args);
free(current_path);
free(controller);

Expand Down Expand Up @@ -885,6 +898,13 @@ int main(int argc, char **argv) {
if (!matlab_path && !get_matlab_path())
return -1;

if (!matlab_args) {
matlab_args = malloc(strlen("-batch") + 1);
sprintf(matlab_args, "-batch");
} else {
printf("Running MATLAB in interactive mode...\n");
}

#ifdef _WIN32
const char *launcher_path = "\\lib\\controller\\matlab";
#elif defined __APPLE__
Expand All @@ -902,7 +922,7 @@ int main(int argc, char **argv) {
char **new_argv = NULL;
new_argv = add_single_argument(new_argv, &current_size, matlab_path);
new_argv = add_single_argument(new_argv, &current_size, matlab_command);
new_argv = add_single_argument(new_argv, &current_size, "-batch");
new_argv = add_single_argument(new_argv, &current_size, matlab_args);
new_argv = add_single_argument(new_argv, &current_size, "launcher");
if (nb_controller_arguments)
new_argv = add_controller_arguments(new_argv, argv, &current_size, true);
Expand Down

0 comments on commit 7e41398

Please sign in to comment.