-
Notifications
You must be signed in to change notification settings - Fork 38
Shared Memory
Luar is a multi-process architecture in that there are multiple processes running simultaneously and at different frequencies. Luar is composed of two main processes: a Motion process and a Cognitive process. The Motion process runs at about 100 updates a second (~100Hz) and the Cognitive process runs at about 30 updates a second (~30Hz).
Of course, there is data that need to be shared between these parallel processes. To accomplish this, Luar uses shared memory. In Luar all shared memory interfaces are handled by special Lua modules called Communication Managers. In general a communication manager will end with *cm.lua (e.g. vcm.lua is the Vision Communication Manager and handles all of the shared memory vision information). The Communication Manager is designed to standardize and abstract all shared memory interfacing and to make adding additional shared memory variables easily.
Every Communication Manager has the following special variables | |
shared |
- A table indicating the shared memory variables to define including the type and size of the variable. - Each member of the shared table indicates a new shared memory segment. - The variables in each segment are indicated by the members of each segment table. |
shsize |
- A table indicating the size of the shared memory segment to create. - You can indicated the total size of the segment by adding it as a key to this table with size of the segment as the value. - The key should be the same used in the shared table. - If no entry exists in the shsize table then the default size (2^16 bytes) is used. |
The second half of the communication managers in the creation of the shared memory segments and accessors for the data.
This is handled by the util.init_shm_segment
function. This functions will only create/destroy a segment or variable if it is needed.
If the segment already exists and is the correct size then the current segment is used. Similarly for variables, new instances are only created if they do not already exist or the existing one is the incorrect size.
The accessors and setter functions are automatically created from the shared table structure. The same basic format is followed for all the segments/variables.
Simply put, the following entry:
shared.[base segment name].[variable name]
will result in the following function definitions to access and set the data respectively:
get_[base segment name]_[variable name]()
set_[base segment name]_[variable name](val)
The following data types are supported | |
number |
- single numbers are indicated by setting the value to a vector of length 1. - NOTE: the accessor will return the number not a vector of length 1. |
vector/array |
- fixed length arrays by setting the value to a vector of length n > 1 - the length of the array is specified by the size of the vector - vector.zeros(4) indicates to the program to create an array of length 4 in the shared memory |
string |
- variable length strings indicated by setting the value to any string - the actual value set in the shared table is ignored, just the fact that it is a string is noted. |
c array |
- fixed size c arrays indicated by setting the value to a number indicating the size in bytes of the array - The accessor/setter for a c array accept and return userdata |
NOTE: When using the setters you must give it a variable of the correct size. (unless it is for the string)
The shared memory segment names are generated based off a few different sources:
- the communication manager creating the segment
- the robots team number
- the robots player ID
- the user account that the code is being run under
The segment name is: [*cm][base segment name (with the first letter capitalized)][team number][player id][user]
For example, the following entry in wcm.lua
:
shared.robot.pose = vector.zeros(3);
will create the shared memory segment: wcmRobot12nao
1 - team number
2 - player id
nao - user
The user is determined by the environment variable $USER
.
The following is how to setup an example Communication Manager we will call Test Communication Manager (tcm) with the lua module tcm.lua.
tcm.lua:
module(..., package.seeall);
require('util');
require('vector');
-- shared properties
shared = {};
shsize = {};
shared.segment1 = {};
shared.segment1.number_a = vector.zeros(1); -- vector of size 1 indicates a number
shared.segment1.vector_b = vector.zeros(3); -- vector of size > 1 indicates an array
shared.segment1.string_c = ' '; -- any string indicates a string (the actual value here is ignored when creating the block)
shared.segment2 = {};
shared.segment2.number_a = vector.zeros(1); -- vector of size 1 indicates a number
-- indicate segment size for segment2
shsize.segment2 = 2^12; -- bytes
-- initialize shared memory segments/variables and create accessors/setters
util.init_shm_segment(getfenv(), _NAME, shared, shsize);
This Communication Manager will have two shared memory segments indicated by the segment1 and segment2 fields in the table shared. The actual segment names for these will be tcmSegment1 and tcmSegment2 respectively and tcmSegment2 will have a total size of 2^12 bytes.
-
The variables in each segment are:
- tcmSegment1
-
number_a - which has a size of 1
vector_b - which has a size of 3
string_c - which is a variable length string - tcmSegment2
- number_a - which has a size of 1
-
The initialization also automatically creates accessors and setters for the shared memory variables:
- tcmSegment1
-
get_segment1_number_a()
get_segment1_vector_b()
get_segment1_string_c()
set_segment1_number_a(val)
set_segment1_vector_b(val)
set_segment1_string_c(val) - tcmSegment2
-
get_segment2_number_a()
set_segment2_number_a(val)
Testing the Test Comminication Manager:
We can test the new tcm.lua module interactively Lua. First, make the tcm.lua file as shown above and open two terminals with an instance of Lua. Each line is a step in time.
Terminal 01 | Terminal 02 |
---|---|
```lua > dofile('init.lua'); > require('tcm') > tcm.set_segment1_number_a(4) > > > > print(tcm.get_segment1_number_a()) 1 > > tcm.set_segment1_vector_b({1,2,3}) > > > tcm.set_segment1_string_c('hello') > > > > print(tcm.get_segment1_string_c()) bye > > print(tcm.get_segment2_number_a()) 2 > ``` | ```lua > dofile('init.lua') > require('tcm') > > print(tcm.get_segment1_number_a()) 4 > tcm.set_segment1_number_a(1) > print(tcm.get_segment1_number_a()) 1 > > > print(tcm.get_segment1_vector_b()) {1, 2, 3} > > print(tcm.get_segment1_string_c()) hello > tcm.set_segment1_string_c('bye') WARNING: Input size 3 != current block size 5. Resizing string_c block. > > tcm.set_segment2_number_a(2) > > > ``` |