Lanciers

From Rsewiki

Lanciers demo robots

Eight of these robots are planned to perform a group performance, similar to one of the tours in Lanciers.

Therefore, the robot is called a dancer, and the robot group manager a dance master.

Hardware

The robot

Each of the robots consists of two motors and a driver board of the same type used by Regbot.

  • Motor is type JGB37-545 with 1:10 or 1:19 gearing and 17 pole encoder (68 ticks per rev).
  • The external gear has 84/24 teeth.
  • The wheel distance is 14.5cm
  • Wheel diameter 7.3cm
  • The robot's total mass is 1.35 kg.
  • Motor mass is 270g each.
  • The PCB mass is 98g.
  • The 2.2 Ah battery mass is 167g.

Dance master

The dance master is a Raspberry Pi.

The communication between the two is a (maybe one-way) LoRa radio connection at 433 MHz.

The dance master obtains the position of each dancer from either Optitrack or by using a camera. The robots are then either equipped with a unique pattern of reflectors or a unique ArUco code.

Radio RFM98W to Regbot 6.3 board

Connector 1 (5-pin JST-ph 2mm)

1 black  - 3.3V
2 red    - SCK
3 white  - MOSI
4 yellow - MISO
5 orange - GND

Connector 2 (line sensor 10-pin connector)

1, 2 NC
3 blue   - DIO0 (tx int)
4 green  - DIO5
5 yellow - reset
6 orange - NSS (CS)
7 red    - DIO1
8 brown  - DIO4
9,10 NC

LoRa radio

The LoRa radio connection uses an RFM98W radio module from HOPERF Electronics.

Connections on RFM98W

ant                  GND
GND      top        DIO5
DIO3     view      reset
DIO4            NSS (CS)
3.3V     RFM         SCK
DIO0     98W        MOSI
DIO1                MISO
DIO2                 GND

Antenna 16cm wire.

Dancer side

On the dancer side, the library used is the RFM98W_library from https://github.com/weustace/LoRaLib.

The configuration is controlled by 6 register values, of which only 4 are used:

 /*  # data sheet
  *  # register
  *  # byte 1: reg 1D, 4msb = BW 7 = 125 kHz, 9 = 500 kHz, 4 = 15.6 kHz
  *  #                 4lsb = error coding 2 = 4/5, 8=4/8
  *  # byte 2: reg 1E, 4msb spreading factor: 7=128 chips / symbol, 9=512 c/s, c=4096 c/s
  *  #                 4lsb mode: 4 = CRC on
  *  # byte 3: reg 09, bit 7=PAboost 1=used, 0=not, bit 6-4 = base power 0=10.8dBm,
  *                    4lsb power reduction 0=full power, 8 = half power f=minimum power (1dBm)
  *  # byte 4,5 not used.
  *  # byte 6: reg 26, 4msb = 0,
  *  #                 4lsb: 4=AGC internal, not mobile, C= AGC internal + mobile node
  */
 // byte my_config[6] = {0x72,0x74,0x8F,0xAC,0xCD, 0x0C}; // fair - Pi ok (too slow)
 byte my_config[6] = {0x92,0x74,0x8F,0xAC,0xCD, 0x0C}; // faster - Pi ok (ca. 15-20 ms per message (10 chars))
 radio.configure(my_config);
 radio.setFrequency(434700000);

This gives the following:

  • The bandwidth used is 125kHz with coding rate of 4/5 (minimal overhead of 25%).
  • Spreading factor 7 increases the sensitivity by 7.5dB
  • Automatic AGC loop and flag as mobile.

The first two values need to be equal on both the receiver and the transmitter.

An interrupt is activated when a message is received. This should enable the rapid implementation of new mission plans without the need for constant polling for messages.

Note that at times, garbage is received, but then the CRC will return false.

Dance master side

The dance master is on the Raspberry Py and uses the pyLoraRFM9x library.

This is configured with 3 bytes:

from pyLoraRFM9x import LoRa, ModemConfig
import time
from enum import Enum
class MC(Enum):
   Bw125Cr45Sf128 = (0x72, 0x74, 0x04) # Radiohead default
   fast = (0x92, 0x74, 0x0C) # a bit too much (500kHz bandwidth)
   fair = (0x72, 0x74, 0x0C) # mobile bit set (used)

The full setup is when the radio is instantiated:

#    LoRa(CS pin, interrupt, ID, port, reset, frq,  Tx power, modem config, ack
lora = LoRa(1,     24,      127,   0,    25, 434.7, 10,        MC.fair,    True)
  • Uses chip select pin 1 (GPIO7, NSS on radio), reset is pin GPIO25, and tx-interrupt is GPIO 24 (DIO0 on radio side).
  • The device port is 0 (pins GPIO9 (MISO), GPIO10 (MOSI), and GPIO11 (CLK).
  • Additionally, 3.3V and ground are connected.
  • In total, 10 pins of the Raspberry Pi connector are used.

Dance master radio interface

Interface cable

IDC on Raspberry to radio
1(red) 17  3.3V      18 GPIO24 - DIO0 - interrupt
3      19  MOSI      20 Ground
5      21  MISO      22 GPIO25 - reset
7      23  CLOCK     24 GPIO08 - NC
9      25  Ground    26 GPIO07 - CS/NSS

On the Raspberry Pi side, a 10-pin header is used, which requires cutting pins 15, 16, 27, and 28.

Python:

from pyLoraRFM9x import LoRa, ModemConfig
import time
from enum import Enum
import timeit
#
# Called when message is received
def on_recv(payload):
 print("From:", payload.header_from)
 print("Received:", payload.message)
 print("RSSI: {}; SNR: {}".format(payload.rssi, payload.snr))
#
#
class MC(Enum):
 Bw125Cr45Sf128 = (0x72, 0x74, 0x04) # Radiohead default
 fast = (0x92, 0x74, 0x0C) # 500kHz BW, mobile bit set
 fair = (0x72, 0x74, 0x0C) # 125kHz BW, mobile bit set
# register ModemConfig
# byte 1: reg 1D, 4msb = BW 7 = 125 kHz, 9 = 500 kHz, 4 = 15.6 kHz
#     4lsb = error coding 2 = 4/5, 8=4/8
# byte 2: reg 1E, 4msb spreading: 7=128 chips/symbol, 9=512 ch/sy, c=4096 ch/sy
#     4lsb mode: 4 = CRC on
# byte 3: reg 26, 4msb = 0, 4lsb: 4=AGC internal, static node, c= AGC internal + mobile node
# LoRa(CS pin, interrupt, ID, port, reset, frq,  Tx power, modem config, ack
lora = LoRa(1,    24,    127,    0,   25, 434.7,   10,     MC.fair,      True)
lora.on_recv = on_recv
#
# Send a message to a recipient device with address 10
# Retry sending the message twice if we don't get an acknowledgement from the recipient
message = "Hello there!"
cnt = 0
while True and message != "quit":
start = time.time()
status = lora.send_to_wait(message, 10, retries=0)
end = time.time()
print("# msg time")
print(end - start)
time.sleep(0.01)
if status is True:
 print("Message sent: " + message)
else:
 print("No acknowledgment from recipient")
cnt += 1
message = input("quit or msg to send >>")
  • It takes about 60ms to send 10 characters with this setting (tested with two only).
  • All receivers get the same message (i.e. the ID number is vital)
  • Runs in a virtual venv environment:

Python virtual environment

Create a virtual environment.

python3 -m venv ~/.venv
source .venv/bin/activate

Install pyLoraRFM9x (from within venv)

pip install --upgrade pyLoraRFM9x 

Enable SPI interface on the Raspberry PI

sudo raspi-config
-> interface options
-> SPI
-> enable

Default activation of venv from .bashrc

Part of .bashrc

# give Python priority to virtual environment (LoRa - comm with RFM98W)
source .venv/bin/activate

Dancer Control

Velocity

The transfer function from motor voltage to wheel velocity gives this Bode plot (from simulation)

This is a standard low-pass system that calls for a PI controller.

On OK design:

  • PI-zero at 30 rad/s, tau_i = 0.043 sec,
  • Feed forward = 7
  • phase margin of 77 degrees,
  • cross-over at 13 rad/s,
  • Kp = 10
  • Low pass in return path tau_pole = 0.007 sec
  • output limit 10V (same for integrator)

Balance

  • Kp = -0.55
  • tau_i = 0.1 (PI integrator)
  • tauii = 0.1 (post integrator)
  • alpha = 0.1 (lead in return path)
  • tau_d = 0.15 (lead in return path)
  • output limit 1.0 (m/s)

Velocity in balance

P-controller

  • Kp = -1.5

Works OK

Dancer software

Dancer software is an extended version of the Regbot software, where IO is extended to accept commands from the LoRa receiver. No return channel is enabled.

Version 0 control parameters:


Firmware

The Lanciers firmware is identical to Regbot firmware.

The radio communication is enabled by

rfmuse 1

It can then be enabled at boot by saving the status to flash

eew

This allows commands to be sent through the radio channel.

Dance master software

To be made.