Cuando trabajamos con el Piloto Automatico de PX4 llamado normalmente "PixHawk", estamos interactuando con una plataforma de Software que corre dentro de este Hardware el cual denominamos Firmware.
Este Firmware, es una plataforma Software de control avanzada que consta de un "Flight Stack" que son algoritos avanzados de navegacion y un Middleware que es la capa de control para toda la robotica implementada.

Arquitectura del Software en el Alto nivel

El siguiente diagrama contiene los bloques del funcionamiento de cada uno de los niveles de ejecucion de la plataforma.
PX4_Architecture

Flight Stack Alto nivel.

Como dije anteriormente, es una pila de algoritmos avanzados para la orientacion, navegacion y control para vehiculos autonomos, incluye control para drones de ala fija, vtol y multirotores, tambien contiene un estimador de altitud y posicion.
PX4_High-Level_Flight-Stack

Middleware

El middleware consiste principalmente en controladores de dispositivos para sensores integrados, comunicación con el mundo externo (computadora como una RaspberryPi, GCS, etc.) y el bus de mensajes de publicación-suscripción uORB.

Además, el middleware incluye una capa de simulación que permite que el código de vuelo PX4 se ejecute en un sistema operativo de escritorio y controle un vehículo modelado por computadora en un "mundo" simulado.

Entorno de Ejecucion "RunTime Environment"

PX4 se ejecuta en varios sistemas operativos que proporcionan una API POSIX (como Linux, macOS, NuttX o QuRT).

La comunicación entre módulos (usando uORB) se basa en la memoria compartida. Todo el middleware PX4 se ejecuta en un único espacio de direcciones, es decir, la memoria se comparte entre todos los módulos.

Informacion del sistema Operativo.

NuttX es el RTOS (Sistema Operativo de Tiempo Real) principal para ejecutar PX4 en una placa de control de vuelo. Es de código abierto (licencia BSD), liviano, eficiente y muy estable.

Los módulos se ejecutan como tareas: tienen sus propias listas de descriptores de archivos, pero comparten un solo espacio de direcciones. Una tarea puede iniciar uno o más hilos que comparten la lista de descriptores de archivos.

Cada tarea / hilo tiene una pila de tamaño fijo, y hay una tarea periódica que comprueba que todas las pilas tengan suficiente espacio libre.

Linux / macOS
En Linux o macOS, PX4 se ejecuta en un único proceso y los módulos se ejecutan en sus propios hilos (no hay distinción entre tareas e hilos como en NuttX)

Laboratorio:

Para este Laboratorio, queremos acceder al dron via Shell NSH, encender las diferentes salidas PWM disponibles para el control de los Aceleradores electronicos conectados sobre cada una de las salidas y ver como actua sobre el motor el valor del pulso enviado.

Componentes:

  • Computador con GNU-Linux (Ubuntu 16.04)
  • Firmware PX4 Compilado
  • Tools PX4
  • Cable USB

Conectando el Hardware.

  • Conectar aqui el piloto automatico al "Power Module" y este a la Tarjeta de distribucion de energia para nuestros Aceleradores Electronicos.
  • Conectar la Bateria al modulo de poder y encender el piloto automatico.
  • Una vez encendido, conectarlo al Computador donde se compilo el Firmware de PX4 con sus Tools.

Aqui suponemos que ya hemos instalado sobre nuestro Piloto el ultimo Firmware Stack de PX4

Si la interfaz se ha conectado correctamente, se vera que sobre el host Linux se montara el dispotivo.

$ sudo dmesg 
[12198.023538] usb 2-1.1: new full-speed USB device number 19 using ehci-pci
[12198.134396] usb 2-1.1: New USB device found, idVendor=26ac, idProduct=0011
[12198.134404] usb 2-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[12198.134408] usb 2-1.1: Product: PX4 FMU v2.x
[12198.134412] usb 2-1.1: Manufacturer: 3D Robotics
[12198.134416] usb 2-1.1: SerialNumber: 0
[12198.136317] cdc_acm 2-1.1:1.0: ttyACM0: USB ACM device

Accediendo a NSH via USB.

Para acceder al Shell de Nuttx que se encuentra sobre el PilotoAutomarico, vamos a necesitar una de las herramientas "Tools" que nos brindan los desarrolladores del proyecto.
para ello accedemos al directorio donde se encuentran las herramientas y inicializamos la comunicacion con el Hardware.

$ cd src/Firmware/Tools/
$ ls -lh
total 648K
-rwxrwxr-x  1 user user  473 jun 22 10:35 adb_upload.sh
-rwxrwxr-x  1 user user 1,3K jun 22 10:35 adb_upload_to_bebop.sh
-rwxrwxr-x  1 user user 2,7K jun 22 10:35 aero_upload.sh
drwxrwxr-x  2 user user 4,0K jun 22 10:35 astyle
-rwxrwxr-x  1 user user 2,5K jun 22 10:35 boot_now.py
-rwxrwxr-x  1 user user 3,0K jun 22 10:35 check_submodules.sh
-rw-rw-r--  1 user user 6,6K jun 22 10:35 CTest2JUnit.xsl
-rwxrwxr-x  1 user user 3,8K jun 22 10:35 decode_backtrace.py
drwxrwxr-x  2 user user 4,0K jun 22 10:35 dist
-rwxrwxr-x  1 user user 2,1K jun 22 10:35 docker_run.sh
drwxrwxr-x  2 user user 4,0K jun 22 10:35 ecl_ekf
-rw-rw-r--  1 user user 6,6K jun 22 10:35 fetch_file.py
-rwxrwxr-x  1 user user  36K jun 22 10:35 fix_headers.sh
-rwxrwxr-x  1 user user 6,3K jun 22 10:35 fsm_visualisation.py
drwxrwxr-x 10 user user 4,0K jun 22 10:40 jMAVSim
-rwxrwxr-x  1 user user  983 jun 22 10:35 jmavsim_run.sh
-rwxrwxr-x  1 user user  12K jun 22 10:35 make_can_boot_descriptor.py
drwxrwxr-x  2 user user 4,0K jun 22 10:35 Matlab
-rw-rw-r--  1 user user 306K jun 22 10:35 mavlink_px4.py
-rwxrwxr-x  1 user user 7,7K jun 22 10:35 mavlink_shell.py
-rwxrwxr-x  1 user user 9,9K jun 22 10:35 mavlink_ulog_streaming.py
drwxrwxr-x  2 user user 4,0K jun 22 10:35 models
-rwxrwxr-x  1 user user 1,1K jun 22 10:35 package_firmware.py
-rw-rw-r--  1 user user   41 jun 22 10:35 posix.gdbinit
-rw-rw-r--  1 user user   56 jun 22 10:35 posix_lldbinit
-rw-rw-r--  1 user user  31K jun 22 10:35 process_sensor_caldata.py
drwxrwxr-x  2 user user 4,0K jun 22 11:00 px4airframes
-rw-rw-r--  1 user user  256 jun 22 10:35 px4_developer.mk.example
drwxrwxr-x  2 user user 4,0K jun 22 10:35 px4moduledoc
-rwxrwxr-x  1 user user 2,2K jun 22 10:35 px4.py
-rwxrwxr-x  1 user user 9,2K jun 22 10:35 px4_snapflight_sanitytest.sh
-rwxrwxr-x  1 user user 4,8K jun 22 10:35 px_mkfw.py
-rwxrwxr-x  1 user user 5,3K jun 22 10:35 px_process_airframes.py
-rwxrwxr-x  1 user user 4,0K jun 22 10:35 px_process_module_doc.py
-rw-rw-r--  1 user user 4,6K jun 22 10:35 px_romfs_pruner.py
-rwxrwxr-x  1 user user  32K jun 22 10:35 px_uploader.py
-rwxrwxr-x  1 user user  242 jun 22 10:35 qgc_meta_sync.sh
-rwxrwxr-x  1 user user 7,6K jun 22 10:35 run-clang-tidy.py
drwxrwxr-x  2 user user 4,0K jun 22 10:35 sdlog2
drwxrwxr-x  2 user user 4,0K jun 22 10:35 setup
-rwxrwxr-x  1 user user  802 jun 22 10:35 setup_gazebo.bash
drwxrwxr-x 10 user user 4,0K jun 22 10:45 sitl_gazebo
-rwxrwxr-x  1 user user 1,4K jun 22 10:35 sitl_multiple_run.sh
-rwxrwxr-x  1 user user 3,7K jun 22 10:35 sitl_run.sh
drwxrwxr-x  2 user user 4,0K jun 22 10:35 stack_usage
-rwxrwxr-x  1 user user 1,3K jun 22 10:35 uavcan_copy.sh
drwxrwxr-x  2 user user 4,0K jun 22 10:35 uorb_graph
-rwxrwxr-x  1 user user 3,3K jun 22 10:35 upload_log.py
-rwxrwxr-x  1 user user  848 jun 22 10:35 upload.sh
-rw-rw-r--  1 user user 1,4K jun 22 10:35 usb_serialload.py

de la lista que se desplega, encontraremos la herramienta "mavlink_shell.py"
para incializarla, debemos tener python 2.7 instalado en el host.

$ python --version
Python 2.7.12

Iniciamos la herramienta

$ python mavlink_shell.py 
Using port /dev/serial/by-id/usb-3D_Robotics_PX4_FMU_v2.x_0-if00
Connecting to MAVLINK...

NuttShell (NSH)
nsh> 

Como podemos evidenciar sobre este paso, hemos accedido al Shell del sistema, el cual es NSH>.
En este punto ya podremos interactuar con el hardware via NSH.

Comandos del Shell y El piloto.

Help

El primer comando a tener encuenta es el uso de "help", este nos mostrara todos los comandos que se pueden usar con la actualizacion actual del firmware.

Al ser Nuttx un sistema operativo Embebido en el piloto automatico, podremos utilizar algunos comandos que son base en algunos sistemas basados en las arquitecturas Unix/Linux como con "cd", "cp", "mv" y "top".

Adicional, tenemos las "Builtin Apps" que son integradas con el Firmware de PX4 sobre el Hardware.

nsh> help
help usage:  help [-v] [<cmd>]

  [           date        free        mount       rmdir       true        
  ?           df          help        mv          set         umount      
  break       echo        kill        mw          sh          unset       
  cat         exec        ls          ps          sleep       usleep      
  cd          exit        mkdir       pwd         test        
  cp          false       mkfatfs     rm          time        

Builtin Apps:
  adc
  bl_update
  camera_feedback
  camera_trigger
  commander
  dataman
  ekf2
  ets_airspeed
  fmu
  fw_att_control
  fw_pos_control_l1
  gps
  hardfault_log
  hmc5883
  l3gd20
  land_detector
  lis3mdl
  ll40ls
  load_mon
  logger
  lsm303d
  mavlink
  mc_att_control
  mc_pos_control
  mixer
  mpu6000
  mpu9250
  ms4525_airspeed
  ms5525_airspeed
  ms5611
  mtd
  navigator
  param
  perf
  pwm_input
  pwm
  px4flow
  px4io
  reboot
  rgbled
  sdp3x_airspeed
  send_event
  sensors
  sf0x
  sf1xx
  srf02
  teraranger
  tfmini
  tone_alarm
  top
  tune_control
  uorb
  ver
  vmount
  vtol_att_control
  sercon
  serdis

En la lista que se acaba de desplegar, podemos evidenciar el comando "pwm" el cual es una App adicional del shell que nos permitira revisar cada una de las 8 diferentes salidas que tiene el piloto automatico para el control de los aceleradores electronicos que mueven los motores.

Sobre este punto es necesario activar el piloto pulsando el "Safe Switch" o Switch de Seguro, sin esto no enviara los datos hacia los pines pwm y no encendera los motores.

Al teclear el comando solo, podemos ver la salida y los parametros que este solicita.

nsh> pwm
Usage: pwm <command> [arguments...]
 Commands:

   arm           Arm output

   disarm        Disarm output

   info          Print current configuration of all channels

   forcefail     Force Failsafe mode
     on|off      Turn on or off

   terminatefail Force Termination Failsafe mode
     on|off      Turn on or off

   rate          Configure PWM rates
     -r <val>    PWM Rate in Hz (0 = Oneshot, otherwise 50 to 400Hz)

   oneshot       Configure Oneshot125 (rate is set to 0)

   failsafe      Set Failsafe PWM value

   disarmed      Set Disarmed PWM value

   min           Set Minimum PWM value

   max           Set Maximum PWM value

   test          Set Output to a specific value until 'q' or 'c' or 'ctrl-c' pressed

   steps         Run 5 steps from 0 to 100%

 The commands 'failsafe', 'disarmed', 'min', 'max' and 'test' require a PWM value:
     -p <val>    PWM value (eg. 1100)

 The commands 'rate', 'oneshot', 'failsafe', 'disarmed', 'min', 'max', 'test' and 'steps' additionally require to specify the channels with one of the following commands:
     [-c <val>]  select channels in the form: 1234 (1 digit per channel, 1=first)
     [-m <val>]  Select channels via bitmask (eg. 0xF, 3)
                 default: 0
     [-g <val>]  Select channels by group (eg. 0, 1, 2. use 'pwm info' to show groups)
                 default: 0
     [-a]        Select all channels

 These parameters apply to all commands:
     [-d <val>]  Select PWM output device
                 values: <file:dev>, default: /dev/pwm_output0
     [-v]        Verbose output
     [-e]        Exit with 1 instead of 0 on error

Confirmamos el estado del puerto con "pwm info"

nsh> pwm info
device: /dev/pwm_output0
channel 1: 900 us (alternative rate: 400 Hz failsafe: 900, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 2: 900 us (alternative rate: 400 Hz failsafe: 900, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 3: 900 us (alternative rate: 400 Hz failsafe: 900, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 4: 900 us (alternative rate: 400 Hz failsafe: 900, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 5: 900 us (alternative rate: 400 Hz failsafe: 900, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 6: 900 us (alternative rate: 400 Hz failsafe: 900, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 7: 0 us (alternative rate: 400 Hz failsafe: 0, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel 8: 0 us (alternative rate: 400 Hz failsafe: 0, disarmed: 900 us, min: 1075 us, max: 1950 us, trim:  0.00)
channel group 0: channels 1 2
channel group 1: channels 5 6 7 8
channel group 2: channels 3 4

Como podremos ver, tenemos un dispositivo que se encarga de proveernos las salidas "/dev/pwm_output0"
tambien tenemos los diferentes canales que estan activos, el rate de actualizacion para el pwm, los valores de minimo y maximo para el tiempo del pulso en microSegundos.
Tambien podremos ver la descripcion de los diferentes grupos y los canales asginados a los mismos.

Para inicializar los puertos, armamos las salidas pwm con el siguiente comando

nsh> pwm arm

Una vez armado podremos encender cada uno de los puertos siguiento la siguiente estructura.

nsh> pwm test -p 1100 -c 1

para cancelar presionamos la tecla "c"
Este comando, inicializa el motor con acelerador electronico por medio del pwm que esta sobre el puerto 1 con un pulso de 1100us.

-p: Valor del pulso en microSegundos, de 900-1950us
-c: numero del puerto, en este caso 1.

Referencias:
https://dev.px4.io/en/concept/architecture.html
https://dev.px4.io/en/middleware/modules_command.html