Use with Webots

Use with Webots — How to use a CPG network to control a robot in Webots

Using a CPG network with webots

Using the CPG library to control a robot in webots can be done fairly easy with the standard API. For instance, if you want to use position control, you can at each webots simulation step get the appropriate property from your network and set some servo devices' position to the value of that property.

CPG network however has a small utility library that makes it even easier to bind properties from the network directly to devices in your webots robot. You can use this functionality by specifying a special property in state containers indicating how the property should be bound to something in webots. The webots device that will be used for this will be matched with the 'id' of the state container.

The following special property names can be used:

  • wb_servo_pos: Set value to servo position (wb_servo_set_position)

  • wb_servo_force: Set value to servo force (wb_servo_set_force)

Similarly, you can read sensor values from webots devices easily into the network by another set of special property names. These properties are handled in a bit of a special way. If they contain a single other property value, the sensor reading will be set to this property instead. So, if you have x = 0 and wb_touch = x, the touch sensor value will be written to x.

The following special property names for sensors can be used:

  • wb_touch: Read value from a touch sensor device

  • wb_light: Read value from a light sensor device

  • wb_gyro_x: Read x value from a gyroscope device

  • wb_gyro_y: Read y value from a gyroscope device

  • wb_gyro_z: Read z value from a gyroscope device

  • wb_gps_x: Read x value from a GPS device

  • wb_gps_y: Read y value from a GPS device

  • wb_gps_z: Read z value from a GPS device

  • wb_accelerometer_x: Read x value from an accelerometer device

  • wb_accelerometer_y: Read y value from an accelerometer device

  • wb_accelerometer_z: Read z value from an accelerometer device

  • wb_compass_x: Read x value from a compass device

  • wb_compass_y: Read y value from a compass device

  • wb_compass_z: Read z value from a compass device

Example controller

The following is an example controller for a simple 3 DOF robot.

Example 1. Example network file

<?xml version="1.0" encoding="utf-8"?>
<cpg>
  <network>
	<globals>
	  <property name="frequency">1</property>
	</globals>
	<templates>
	  <state id="oscillator">
		<property name="P">0</property>
		<property name="phase" integrated="yes">P</property>
		<property name="amplitude">1</property>
		
		<!-- Use the special 'wb_servo_pos' to bind to servo position -->
		<property name="wb_servo_pos">amplitude * sin(phase)</property>
	  </state>
	  <link id="integration">
		<action target="phase">2 * PI * frequency</action>
	  </link>
	</templates>
	
	<!-- States -->
	<state id="servo_1" ref="oscillator">
	  <property name="amplitude">2</property>
	  <property name="P">0</property>
	</state>
	<state id="servo_2" ref="oscillator">
	  <property name="amplitude">1</property>
	  <property name="P">0.5 * PI</property>
	</state>
	<state id="servo_3" ref="oscillator">
	  <property name="amplitude">3</property>
	  <property name="P">PI</property>
	</state>
	
	<!-- Integration links -->
	<link id="integrate_servo_1" ref="integration" from="servo_1" to="servo_1"/>
	<link id="integrate_servo_2" ref="integration" from="servo_2" to="servo_2"/>
	<link id="integrate_servo_3" ref="integration" from="servo_3" to="servo_3"/>
  </network>
</cpg>
  

Example 2. Example controller

#include <cpg-network-webots/cpg-network-webots.h>
#include <stdio.h>

#define WEBOTS_STEP 5

static CpgNetwork *
read_network(char const *filename)
{
	CpgNetwork *network;
	CpgCompileError *error;
	GError *load_error = NULL;
	
	network = cpg_network_new_from_file ("network.cpg", &load_error);

	if (network == NULL)
	{
		fprintf (stderr, 
				 "Could not read network: %s\n",
				 load_error ? load_error->message : "Unknown");

		if (load_error != NULL)
		{
			g_error_free (load_error);
		}

		return NULL;
	}
	
	error = cpg_compile_error_new ();

	if (!cpg_network_compile (network, error))
	{
		fprintf (stderr, 
				 "Could not compile network: %s", 
				 cpg_compile_error_string (error));

		cpg_ref_counted_unref (error);
		return NULL;
	}
	
	cpg_ref_counted_unref (error);
	return network;
}

int main(int argc, char **argv)
{
	CpgNetwork *network;
	CpgNetworkWebots *network_webots;
	
	g_type_init ();
	network = read_network ("network.cpg");

	if (network == NULL)
	{
		return 1;
	}
	
	wb_robot_init ();
	network_webots = cpg_network_webots_new (network);
	
	while (wb_robot_step (WEBOTS_STEP) != -1)
	{
		int i;
		
		/* Update bindings */
		cpg_network_webots_update (network_webots);
		
		/* Run network simulation */
		for (i = 0; i < WEBOTS_STEP; ++i)
		{
			cpg_network_step (network, 0.001);
		}
	}
	
	g_object_unref (network);
	wb_robot_cleanup ();
	
	return 0;
}
  

Note

You can compile the example like: gcc -o controller controller.c -lController -L/usr/local/webots/lib -I/usr/local/webots/include/controller/c `pkg-config --cflags --libs cpg-network-webots-1.0`

Note

The webots bindings can be used with webots 6.1 and higher