{
  "product": "Spectral Micro",
  "firmware": "V107",
  "commit": "2e7febc4de63",
  "byte_order": "big-endian",
  "bitrate": 1000000,
  "commands": [
    {
      "key": "IN_DATA_PACK_1",
      "id": 2,
      "name": "Send_data_pack_1",
      "description": "The motion command. Its length decides the control mode the driver enters: 8 bytes command a position with a speed and a current feedforward, 5 bytes a speed with a current feedforward, 2 bytes a current. Send 0 for a feedforward you do not use. A frame of any other length is ignored (the driver flags it as a wrong data length) but still answered.",
      "forms": [
        {
          "direction": "host",
          "length": 8,
          "remote": false,
          "title": "position setpoint with speed and current feedforward (position mode)",
          "fields": [
            {
              "name": "Position setpoint",
              "byte": 0,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks"
            },
            {
              "name": "Speed feedforward",
              "byte": 3,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks/s"
            },
            {
              "name": "Current feedforward",
              "byte": 6,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "mA"
            }
          ]
        },
        {
          "direction": "host",
          "length": 5,
          "remote": false,
          "title": "speed setpoint with current feedforward (velocity mode)",
          "fields": [
            {
              "name": "Speed setpoint",
              "byte": 0,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks/s"
            },
            {
              "name": "Current feedforward",
              "byte": 3,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "mA"
            }
          ]
        },
        {
          "direction": "host",
          "length": 2,
          "remote": false,
          "title": "current setpoint (current mode)",
          "fields": [
            {
              "name": "Current setpoint",
              "byte": 0,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "mA"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_DATA_PACK_PD",
      "id": 4,
      "name": "Send_data_pack_PD",
      "description": "Puts the driver in impedance (PD) mode and sets the position, speed and current feedforward of the PD loop, whose gains are KP and KD (Send_PD_Gains).",
      "forms": [
        {
          "direction": "host",
          "length": 8,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Position setpoint",
              "byte": 0,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks"
            },
            {
              "name": "Speed setpoint",
              "byte": 3,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks/s"
            },
            {
              "name": "Current feedforward",
              "byte": 6,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "mA"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_DATA_PACK_1",
      "id": 3,
      "name": "Respond_data_pack_1",
      "description": "The driver's answer to Send_data_pack_1 and Send_data_pack_PD: where the motor is, how fast it turns and the current it draws. The Python library stores them as `position`, `speed` and `current`.",
      "forms": [
        {
          "direction": "driver",
          "length": 8,
          "remote": false,
          "title": "driver feedback",
          "fields": [
            {
              "name": "position",
              "byte": 0,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks"
            },
            {
              "name": "speed",
              "byte": 3,
              "size": 3,
              "bits": null,
              "width": 24,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks/s"
            },
            {
              "name": "current",
              "byte": 6,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "Iq in mA"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_KP_KD",
      "id": 16,
      "name": "Send_PD_Gains",
      "description": "Sets KP and KD, the gains of the impedance (PD) loop. Keep them with Send_Save_config.",
      "forms": [
        {
          "direction": "host",
          "length": 8,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "KP",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            },
            {
              "name": "KD",
              "byte": 4,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            }
          ]
        }
      ]
    },
    {
      "key": "IN_KIIQ_KPIQ",
      "id": 17,
      "name": "Send_Current_Gains",
      "description": "Sets Kp and Ki of the PI current loop of Iq. The Id loop keeps its gains; over UART, `#Kpiq` and `#Kiiq` set both loops.",
      "forms": [
        {
          "direction": "host",
          "length": 8,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Kp_iq",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            },
            {
              "name": "Ki_iq",
              "byte": 4,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            }
          ]
        }
      ]
    },
    {
      "key": "IN_KPV_KIV",
      "id": 18,
      "name": "Send_Velocity_Gains",
      "description": "Sets Kp and Ki of the PI velocity loop.",
      "forms": [
        {
          "direction": "host",
          "length": 8,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Kpv",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            },
            {
              "name": "Kiv",
              "byte": 4,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            }
          ]
        }
      ]
    },
    {
      "key": "IN_KPP",
      "id": 19,
      "name": "Send_Position_Gains",
      "description": "Sets Kp of the P position loop.",
      "forms": [
        {
          "direction": "host",
          "length": 4,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Kpp",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": ""
            }
          ]
        }
      ]
    },
    {
      "key": "IN_LIMITS",
      "id": 20,
      "name": "Send_Limits",
      "description": "Sets the speed limit and the current limit the loops may reach. The firmware stores the current limit as it arrives: over CAN it is not clamped to the driver's 2800 mA (only `#Ilim` over UART clamps it). Never send more than 2800 mA, or more than the motor's rating.",
      "forms": [
        {
          "direction": "host",
          "length": 8,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Speed limit",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": "encoder ticks/s"
            },
            {
              "name": "Current limit",
              "byte": 4,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": "mA"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_KT",
      "id": 22,
      "name": "Send_Kt",
      "description": "Sets the motor's torque constant Kt, which the driver uses to estimate torque from current.",
      "forms": [
        {
          "direction": "host",
          "length": 4,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Kt",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": "Nm/A"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_VLIM",
      "id": 34,
      "name": "Send_Voltage_Limit",
      "description": "Sets the voltage limit of the current loops (the same value as `#Vlim`), in mV. 0 means use the supply voltage. In the 104 release image (the source at tag V104 does not have it yet) and in every release from 105.",
      "forms": [
        {
          "direction": "host",
          "length": 4,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Voltage limit",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "mV; 0 = Vbus"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_PING",
      "id": 10,
      "name": "Send_Respond_Ping",
      "description": "Asks the driver to answer with an empty frame, to see that it is on the bus.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 0,
          "remote": false,
          "title": "reply",
          "fields": []
        }
      ]
    },
    {
      "key": "OUT_IN_TEMPERATURE_CAN",
      "id": 23,
      "name": "Send_Respond_Temperature",
      "description": "Asks for the thermistor temperature. Meaningful only with the thermistor enabled (`#Term 1`).",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 2,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "temperature",
              "byte": 0,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "\u00b0C"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_VOLTAGE_CAN",
      "id": 24,
      "name": "Send_Respond_Voltage",
      "description": "Asks for the supply voltage.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 2,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "voltage",
              "byte": 0,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "mV"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_DEVICE_INFO_CAN",
      "id": 25,
      "name": "Send_Respond_Device_Info",
      "description": "Asks for the driver's identity: hardware version, batch date and serial number from the EEPROM, and the firmware release (from firmware 105 on this is the build's own version; before, a value from the EEPROM).",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 7,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "HARDWARE_VERSION",
              "byte": 0,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "PCB revision"
            },
            {
              "name": "BATCH_DATE",
              "byte": 1,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "production batch, the lowest 8 bits of the stored value (24092024 after #Default is sent as 120)"
            },
            {
              "name": "SOFTWARE_VERSION",
              "byte": 2,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "firmware release, e.g. 107"
            },
            {
              "name": "SERIAL_NUMBER",
              "byte": 3,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "serial number"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_STATE_OF_ERRORS_CAN",
      "id": 26,
      "name": "Send_Respond_State_of_Errors",
      "description": "Asks for every error flag and the calibrated, activated and watchdog states.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 2,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "error",
              "byte": 0,
              "size": 1,
              "bits": [
                7
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "any error is active"
            },
            {
              "name": "temperature_error",
              "byte": 0,
              "size": 1,
              "bits": [
                6
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "motor over the temperature limit"
            },
            {
              "name": "encoder_error",
              "byte": 0,
              "size": 1,
              "bits": [
                5
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "magnet not detected or misaligned"
            },
            {
              "name": "vbus_error",
              "byte": 0,
              "size": 1,
              "bits": [
                4
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "supply voltage outside the limits"
            },
            {
              "name": "driver_error",
              "byte": 0,
              "size": 1,
              "bits": [
                3
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the MOSFET driver reports undervoltage, thermal shutdown or overcurrent"
            },
            {
              "name": "velocity_error",
              "byte": 0,
              "size": 1,
              "bits": [
                2
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "speed over the limit"
            },
            {
              "name": "current_error",
              "byte": 0,
              "size": 1,
              "bits": [
                1
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "reserved; never set by this firmware"
            },
            {
              "name": "estop_error",
              "byte": 0,
              "size": 1,
              "bits": [
                0
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "Send_ESTOP was received"
            },
            {
              "name": "calibrated",
              "byte": 1,
              "size": 1,
              "bits": [
                7
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the motor is calibrated"
            },
            {
              "name": "activated",
              "byte": 1,
              "size": 1,
              "bits": [
                6
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the controller is activated"
            },
            {
              "name": "watchdog_error",
              "byte": 1,
              "size": 1,
              "bits": [
                5
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the watchdog ran out"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_IQ",
      "id": 27,
      "name": "Send_Respond_Iq_data",
      "description": "Asks for the measured Iq current.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 2,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "current",
              "byte": 0,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "mA"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_ENCODER",
      "id": 28,
      "name": "Send_Respond_Encoder_data",
      "description": "Asks for the position and the filtered speed, as 32-bit values. Python attributes `position` and `speed`.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 8,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "position",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks"
            },
            {
              "name": "speed",
              "byte": 4,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "encoder ticks/s"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_IN_KT",
      "id": 33,
      "name": "Send_Respond_Kt",
      "description": "Asks for the torque constant Kt the driver uses. Added in firmware 104.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": true,
          "title": "status request (RTR)",
          "fields": []
        },
        {
          "direction": "driver",
          "length": 4,
          "remote": false,
          "title": "reply",
          "fields": [
            {
              "name": "Kt",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": true,
              "lsb_first": false,
              "meaning": "Nm/A"
            }
          ]
        }
      ]
    },
    {
      "key": "OUT_HEARTBEAT",
      "id": 9,
      "name": "Respond_Heartbeat",
      "description": "The frame the driver sends on its own at the heartbeat interval (Send_Heartbeat_Setup); empty. Off by default. Any other frame the driver sends resets the heartbeat timer, so a driver that answers motion commands at a high rate never sends a heartbeat.",
      "forms": [
        {
          "direction": "driver",
          "length": 0,
          "remote": false,
          "title": "driver feedback",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_CAN_ID",
      "id": 11,
      "name": "Send_CAN_ID",
      "description": "Gives the driver a new node ID, 0 to 13 (the firmware accepts up to 15, but the bootloader reserves 14 and 15: a driver on one of those cannot be updated over CAN). The driver answers to the new ID at once. The ID is kept over a power cycle only after Send_Save_config, and saving is also what copies it into the bootloader's board ID.",
      "forms": [
        {
          "direction": "host",
          "length": 1,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "ID",
              "byte": 0,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "0 to 13 (14 and 15 are accepted but reserved by the bootloader)"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_ESTOP",
      "id": 0,
      "name": "Send_ESTOP",
      "description": "Stops the motor and raises the E-stop error, which stays until Send_Clear_Error.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "command",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_IDLE",
      "id": 12,
      "name": "Send_Idle",
      "description": "Puts the driver in idle mode: the motor coasts, or brakes when Send_Settings or `#Brake 1` asked for it.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "command",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_SAVE_CONFIG",
      "id": 13,
      "name": "Send_Save_config",
      "description": "Writes the current configuration (gains, limits, calibration, CAN ID, heartbeat, watchdog, gripper flag) to the EEPROM, and copies the CAN ID into the bootloader's board ID.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "command",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_RESET",
      "id": 14,
      "name": "Send_Reset",
      "description": "Resets the driver. From firmware 104 the reset lands in the bootloader, which waits 2 s for a flashing host and then starts the firmware again; this is how a firmware update begins.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "command",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_CLEAR_ERROR",
      "id": 1,
      "name": "Send_Clear_Error",
      "description": "Clears the error flags and goes to idle. An error whose cause is still present comes straight back. A calibration error is cleared only by calibrating.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "command",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_WATCHDOG_TIMEOUT",
      "id": 15,
      "name": "Send_Watchdog",
      "description": "Sets the watchdog. The motion commands (Send_data_pack_1, Send_data_pack_PD, Send_gripper_data_pack) and the status requests (the Send_Respond_ remote frames) reset it; the other frames and UART commands do not. When the time runs out the driver reports a watchdog error and disables the motor, which then coasts. 0 turns it off (the default). The action byte is stored but not acted on by this firmware. The setting is kept by Send_Save_config and there is no UART command for it: to turn off a saved watchdog, send 0 over CAN and save, or use `#Default`.",
      "forms": [
        {
          "direction": "host",
          "length": 5,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Time",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "ms; 0 = off"
            },
            {
              "name": "Action",
              "byte": 4,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "0 idle, 1 hold, 2 brake (stored only)"
            }
          ]
        }
      ]
    },
    {
      "key": "HEARTBEAT_SETUP",
      "id": 30,
      "name": "Send_Heartbeat_Setup",
      "description": "Sets the heartbeat interval in ms; 0 turns the heartbeat off (the default). Kept by Send_Save_config.",
      "forms": [
        {
          "direction": "host",
          "length": 4,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Interval",
              "byte": 0,
              "size": 4,
              "bits": null,
              "width": 32,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "ms; 0 = off"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_SETTINGS",
      "id": 35,
      "name": "Send_Settings",
      "description": "Sets boolean settings that have no command of their own: a mask byte says which settings the frame touches, a value byte gives their new values; settings outside the mask are left alone. Bit 0 is the idle behaviour: 1 brake (phases shorted), 0 coast (the default). The setting is not saved: the driver coasts again after a power cycle. Braking applies only in idle without an error; an error always disables the motor, which then coasts. The braking current is not limited, see Control modes. Added in firmware 107 (STEPFOC 107). The Python library has no call for it yet.",
      "forms": [
        {
          "direction": "host",
          "length": 2,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Mask",
              "byte": 0,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "bit 0 = write the idle behaviour"
            },
            {
              "name": "Value",
              "byte": 1,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "bit 0: 1 brake, 0 coast"
            }
          ]
        }
      ]
    },
    {
      "key": "IN_GRIPPER_DATA_PACK",
      "id": 61,
      "name": "Send_gripper_data_pack",
      "description": "The gripper command, for a driver set up as a gripper (`#Gripper 1`, saved). Position, speed and the current limit of the move, plus the activate, action and E-stop bits. A move is carried out only while the gripper is calibrated, activated and the action bit is 1. An empty frame (0 bytes) only asks for the state.",
      "forms": [
        {
          "direction": "host",
          "length": 5,
          "remote": false,
          "title": "command",
          "fields": [
            {
              "name": "Position",
              "byte": 0,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "0 fully open, 255 fully closed"
            },
            {
              "name": "Speed",
              "byte": 1,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "0 slowest, 255 fastest"
            },
            {
              "name": "Current",
              "byte": 2,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "current limit of the move in mA; not clamped by the firmware, see the gripper manual for the safe range"
            },
            {
              "name": "Activate",
              "byte": 4,
              "size": 1,
              "bits": [
                7
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "1 activate the gripper, 0 deactivate"
            },
            {
              "name": "Action",
              "byte": 4,
              "size": 1,
              "bits": [
                6
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "1 go to the position, 0 idle"
            },
            {
              "name": "E-stop",
              "byte": 4,
              "size": 1,
              "bits": [
                5
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "1 raises the gripper E-stop error"
            },
            {
              "name": "Release direction",
              "byte": 4,
              "size": 1,
              "bits": [
                4
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "read by the firmware but not used"
            }
          ]
        },
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "status poll",
          "fields": []
        }
      ]
    },
    {
      "key": "IN_GRIPPER_CALIB",
      "id": 62,
      "name": "Send_gripper_calibrate",
      "description": "Starts the gripper calibration (the jaws find their end stops). Needed after every power-up.",
      "forms": [
        {
          "direction": "host",
          "length": 0,
          "remote": false,
          "title": "command",
          "fields": []
        }
      ]
    },
    {
      "key": "OUT_GRIPPER_DATA_PACK",
      "id": 60,
      "name": "Respond_Gripper_data_pack",
      "description": "The driver's answer to Send_gripper_data_pack: position, measured current, and the state bits. Python attributes `gripper_position`, `gripper_current`, `gripper_activated`, `gripper_action_status`, `gripper_object_detection`, `gripper_temperature_error`, `gripper_timeout_error`, `gripper_estop_error`, `gripper_calibrated`.",
      "forms": [
        {
          "direction": "driver",
          "length": 4,
          "remote": false,
          "title": "driver feedback",
          "fields": [
            {
              "name": "gripper_position",
              "byte": 0,
              "size": 1,
              "bits": null,
              "width": 8,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "0 fully open, 255 fully closed"
            },
            {
              "name": "gripper_current",
              "byte": 1,
              "size": 2,
              "bits": null,
              "width": 16,
              "signed": true,
              "float": false,
              "lsb_first": false,
              "meaning": "measured current in mA"
            },
            {
              "name": "gripper_activated",
              "byte": 3,
              "size": 1,
              "bits": [
                7
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "1 activated"
            },
            {
              "name": "gripper_action_status",
              "byte": 3,
              "size": 1,
              "bits": [
                6
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the action bit of the last Send_gripper_data_pack (1 after #Grippos); the driver never clears it, so it stays 1 after the move ends: the object detection tells when the move has ended"
            },
            {
              "name": "gripper_object_detection",
              "byte": 3,
              "size": 1,
              "bits": [
                5,
                4
              ],
              "width": 2,
              "signed": false,
              "float": false,
              "lsb_first": true,
              "meaning": "bit 5 is the low bit, bit 4 the high bit: 0 moving, 1 object detected while closing, 2 object detected while opening, 3 at the position"
            },
            {
              "name": "gripper_temperature_error",
              "byte": 3,
              "size": 1,
              "bits": [
                3
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the driver's temperature error"
            },
            {
              "name": "gripper_timeout_error",
              "byte": 3,
              "size": 1,
              "bits": [
                2
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "the driver's watchdog error: the CAN watchdog ran out"
            },
            {
              "name": "gripper_estop_error",
              "byte": 3,
              "size": 1,
              "bits": [
                1
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": ""
            },
            {
              "name": "gripper_calibrated",
              "byte": 3,
              "size": 1,
              "bits": [
                0
              ],
              "width": 1,
              "signed": false,
              "float": false,
              "lsb_first": false,
              "meaning": "1 calibrated"
            }
          ]
        }
      ]
    }
  ]
}
