Basestation#

Motivation The old base station node was tedious to configure, and doesn’t integrate well with the node framework. Furthermore, it doesn’t support hot plugging or dynamic configuration, and must be restarted in order to change the configuration. The old base station also had the requirement for 1-1 functions, which means we can only implement functionality such as tank drive with override functions which were cumbersome to use.The new base station node solves all of these problems. The new design allows us to have different basestations with different control schemes.

New Design The purpose of base station nodes are to take these raw values outputted by joystick nodes, manipulate them, and publish them to the appropriate endpoints. They can do this easily by defining a linear transformation between the input joystick vector and the output vector. Each base station node will depend on the joysticks it needs. In order to support multiple configurations, we will have different instances of the same base station node.

Using matrices, we can support arbitrary transformations on input vectors. This includes transformations that are not 1-1, supporting the problem mentioned above. While these transformations may not be exactly linear as we clamp the output before publishing, we can get the desired effects or arbitrary and configurable control schemes.

Different Configurations We can have multiple base station nodes for each configuration for each subsystem of the rover, and can potentially run multiple ones at the same time, as well as easily swap some out by disabling old ones and enabling new ones. For example, you might have one base station node configured for drive, and another configured for person A’s arm driving, and another for person B’s arm driving. You could have both the drive and A arm drive enabled at the same time, and then switch the arm drive to person B’s very easily.

Creating A Base Station This tutorial will walk through designing a unique basestation configuration

Boilerplate All joystick nodes will start with the following code:

node:

max_restart_attempts: 1 restart_delay: 1000

type: cmr_bs/bs_node The integer values on node can be changed to reflect the performance you want out of your basestation node

Dependencies Any controller that this basestation will read from is a dependency of the basestation configuration. For example, if we had a basestation node that needed our Logitech and thrustmaster controllers, we would need the following under our dependencies section of our config file:

dependencies:
joy1:

type: cmr_bs/joystick_node path: /joysticks/thrustmaster

joy2:

type: cmr_bs/joystick_node path: /joysticks/logitech

The type of these dependencies must be cmr_bs/joystick_node. The path should be /joystick/<name_of_joystick>. The name of the joystick means that there exists some .yaml file for a joystick_node by that name. In the case of the example code above, this implies there exists thrustmaster.yaml and logitech.yaml.

Internal General Info All basestations will have the following fields

publishing_frequency: 1.0 joyreading_timeout: 2000 which represent the name of the basestation, the frequency with which the basestation publishes to its listeners and the maximum amount of time between hearing from joysticks until it declares them lost and shuts down the basestation. It is important that this number be greater than the publishing frequency of all dependent joystick or the node will shut down almost immediately after start up.

Input Joysticks define their inputs by YAML sequences such as

input:
  • [joy1, axes, 1]

  • [joy2, axes, 3]

  • [joy1, axes, 4]

  • [joy1, axes, 5]

Each input defines, in this order, the joystick dependency to listen to (as named in the dependencies section above), the field of the joystick message you want to listen to (present time capabilities limit this to “axes” or “buttons”), and the index of the input array that should be listened to.

Output Joysticks define their output by YAML sequences as well

output:
  • /rover/drive/left_bank

  • /rover/drive/right_bank

  • /rover/arm/elbow

  • /rover/util/pan

There are the topics that the output vector will publish to. The order in which they are listed represents the index of the output array that they will get published to that topic. That is, the value at index 0 of the output array will be published to /rover/drive/left_bank, index 1 to /rover/drive/right_bank and so on. These values are published as Float64s

Modifiers There are times where we want non-linear transformations on our output. For example, halving the speed of the wheels. This is done using the optional modifications section of basestations. To implement half speed with the example output above, we could have:

modifications:
  • [[joy1, buttons, 6], .5, 0]

  • [[joy1, buttons, 6], .5, 1]

When the 6th index button on joy1 is pressed, the outputs at index 0 and index 1 will be multiplied by .5. The configuration format is [<Input Topic>, <Multiplier>, <Output Index Location>], where Input Topic is defined as in the Inputs section above.

Limits Basestations can limit the maximum and minimum values of the input vectors they receive and output vectors they publish.

limits:
input:

lower: [-1, -1, -1] upper: [1, 1, 1]

output:

lower: [-50, -50, -50, -50] upper: [50, 50, 50, 50]

Any value that is below a lower limit will be changed to that limit, and likewise for upper. Input values are clamped upon receiving, and output values are clamped after transformation.

Transformation The key part to the functionality of the basestation node is that all the basestation does is perform a vector multiplication. The input vector is multiplied by a unique transformation matrix that produced a desired output vector.

transform:
  • [10, -9, 0]

  • [0, 1, 0]

  • [0, 22, 6]

  • [9, 10, 0]

The dimensions of this matrix must be number of outputs by number of inputs. This allows us to do arbitrary transformations. For example, looking at the first row of the matrix above, we can implement a drive and a slow-roll with this row. If we use the vector defined in Inputs, then an axes reading will be the first value in the input vector, a button the second. When the axes is pushed full_throttle, its value get multiplied by 10, but when the button is pressed, that values get decreased down to 1. Thus, the motion is slowed.

Running the BaseStation Use cmr base to launch the basestation and cmr enable base/<name_of_bs>. Use cmr switch <base/name_of_bs> to switch from the current basestation to the basestation you want to be running. To restart a basestation node, you can use cmr restart base/<name_of_bs>.