Software Movement and animations - makerforgetech/modular-biped GitHub Wiki

Introduction

The movement of the leg and neck servos is managed directly by the Arduino. The range of each servo is defined in code and can be calibrated manually. See the MakerForge.tech post and video for more information.

The Arduino sketch includes basic inverse kinematics to calculate the leg height and also integrates with an MPU6050 inertial measurement unit (IMU) to balance the relative angle of the body. These aspects are also controlled directly by the Arduino when needed.

The Arduino can assume complete control of the robot's movement to trigger random movement and animation, or can receive instructions via serial from the Raspberry Pi or other single board computer (SBC).

Raspberry Pi Controlled Movement

The Raspberry Pi can assume control of the servos by issuing instructions over serial.

In order to send instructions to the Arduino for movement, the Raspberry Pi utilises the robust_serial library wrapped in a custom module ArduinoSerial located within modules/network/arduinoserial.py.

Ref: Arduino Serial Module

However, the default approach to managing servos is using the Servo module which subscribes to the pubsub topics servo:[identifier]:mvabs and servo:[identifier]:mv for absolute and relative servo positioning respectively.

Ref: Servo Module

pub.sendMessage('servo:[identifier]:mvabs', percentage): Move servo [identifer] to an absolute position (0 - 100) pub.sendMessage('servo:[identifier]:mv', percentage): Move servo [identifer] to a position relative to the current position (0 - 100)

Identifiers are defined as the index in the config/servos.yml:

servos:
  enabled: true
  path: "modules.actuators.servo.Servo" # Include class name here
  instances:
    - name: "leg_l_hip"
      id: 0
      pin: 9
      range: [0, 180]
      start: 40
    - name: "leg_l_knee"
      id: 1
      pin: 10
      range: [0, 180]
      start: 10
    - name: "leg_l_ankle"
      id: 2
      pin: 11
      range: [5, 165]
      start: 100
    - name: "leg_r_hip"
      id: 3
      pin: 6
      range: [0, 180]
      start: 60
    - name: "leg_r_knee"
      id: 4
      pin: 7
      range: [0, 180]
      start: 90
    - name: "leg_r_ankle"
      id: 5
      pin: 8
      range: [10, 180]
      start: 0
    - name: "tilt"
      id: 6
      pin: 2
      range: [60, 120]
      start: 50
    - name: "pan"
      id: 7
      pin: 3
      range: [30, 150]
      start: 50

Ref: Servo Config

For example, the above can be used to manage precise servo movement, such as object tracking:

pub.sendMessage('servo:pan:mv', percentage=[amount]) pub.sendMessage('servo:tilt:mv', percentage=[amount])

This approach delegates pin management, servo identification and range management to the configuration file.

(Note that the range and start position should match the values programmed in the Arduino sketch.)

Animations

As servo positioning can be complex, a preset list of animations are available via the animate pubsub topic.

pub.sendMessage('animate', action='celebrate')

Each animation is stored in the animations directly, simply pass the name of the .json to the animate topic's action parameter.

Directory of Animations

Ref: Animation Module

Examples

# Start
print('Moving')
# Full Right
pub.sendMessage('servo:pan:mvabs', percentage=0)
sleep(5)
# Full Left
pub.sendMessage('servo:pan:mvabs', percentage=100)
sleep(5)
# Center
pub.sendMessage('servo:pan:mvabs', percentage=50)
sleep(5)
# Down
pub.sendMessage('servo:tilt:mvabs', percentage=100)
sleep(5)
# Up
pub.sendMessage('servo:tilt:mvabs', percentage=0)
sleep(5)
# Down a little
pub.sendMessage('servo:tilt:mv', percentage=10)
sleep(1)
# Down a little more
pub.sendMessage('servo:tilt:mv', percentage=10)
sleep(1)
# Down a little more
pub.sendMessage('servo:tilt:mv', percentage=10)
sleep(1)
# Center
pub.sendMessage('servo:tilt:mvabs', percentage=50)
sleep(5)
# Shake Head
pub.sendMessage('animate', action='head_shake')
sleep(5)

# Legs
# Stand
pub.sendMessage('animate', action='stand')
# sleep(2)
# Sit
# pub.sendMessage('animate', action='sit')
sleep(2)

print('Done')

ArduinoSerial

The Servo module should be used to send servo instructions, but the option exists to bypass this module and utilise the ArduinoSerial module to send instructions to the Arduino directly.

When initialised, the ArduinoSerial module allows data to be sent to the Arduino via serial, using the pubsub topic serial, passing an identifier and message:

pub.sendMessage('serial', type, identifier, message)

Note: The Servo module maps the identifier to an ID automatically. If interacting with the servos directly via the serial topic this must be done manually. The identifier is not the pin, the mapping to pin from ID takes place in the Arduino ServoManager sketch.

Message types

The following types are possible:

  • ArduinoSerial.DEVICE_SERVO: Instructions for servo movement
  • ArduinoSerial.DEVICE_SERVO_READ: Instructions for servo movement, relative to current position.
  • ArduinoSerial.DEVICE_PIN: Instruction to change pin value
  • ArduinoSerial.DEVICE_PIN_READ: Read pin value (such as battery voltage)
  • ArduinoSerial.DEVICE_LED: Instructions for neopixels connected to the Arduino (not currently in use)

Servo Movement

When a servo type is passed (either absolute or relative), the identifier should include the identifier of the servo or list of identifiers to move.

The message should then be a value between 0 and 100 representing the percentage value (or change, if relative) of the servo.

Pi Servo Control

The head also has a single servo connected that is controlled directly by the Raspberry Pi. This is managed by the PiServo module located in modules/actuators/piservo.py.

This module currently controls a single servo but could be adapted to control multiple servos if required (assuming pin availability).