Infineon Team
Published © MIT

Pneumatic Octocat Coming to Life

See the world-renown GitHub logo alive with the help of the DC Motor Control HAT from Infineon.

AdvancedFull instructions providedOver 8 days510
Pneumatic Octocat Coming to Life

Things used in this project

Hardware components

TLE94112ES Raspberry Pi HAT
Infineon TLE94112ES Raspberry Pi HAT
×1
Electric pneumatic solenoid valve
×10
5-way pneumatic distributor connection
×2
Push-in fitting Pneumatics (4mm)
×20
Push-in fitting Pneumatics (8mm)
×11
Pneumatic T Push to Connect Fitting Kits
×1
Pneumatic Hose connection
×10
Compressed air plug-in nipple (connection to compressor)
×1
water soluble filament
×1
Pouring silicone
×1
Black colour pigment
×1
Compressor
×1

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Vacuum chamber with vacuum pump
Pouring tools: separation spray, measuring jug, stirring rod, gloves, fine scale and one-hand clamp

Story

Read more

Custom parts and enclosures

Tentacle canal

OctoCat Head Front

OctoCat Head Back

Tentacle mold

Stator

Code

C++ Code to bring the Octocat to life

C/C++
This is the whole code to control the TLE94112ES RaspberryPi-HAT and therefore bring the Octocat to life.
/*!
 * \name        halfBridge
 * \author      Infineon Technologies AG
 * \copyright   2021 Infineon Technologies AG
 * \brief       This example shows how to control the independent half bridges of the multi half bridge ICs.
 * \details
 * The example shows how to control the half bridges to switch generic loads.
 *
 * SPDX-License-Identifier: MIT
 *
 */

/* Infineon library for multi half bridge */
#include "tle94112-rpi.hpp"

#include <bcm2835.h> // This library is required for the delay() function.

#include <cstdio>

#define MOVEMENT_INTERVAL 30000

void log(const char* message) {
  printf("[...");
  printf("]\t");
  printf(message);
  printf("\n");
}

void log(const char* unit, const char* message) {
  printf("[");
  printf(unit);
  printf("]\t");
  printf(message);
  printf("\n");
}

class Octocat {
  public:
    Tle94112Rpi *controller;
    Octocat (Tle94112Rpi &driver) {
      controller = &driver;
    };
    uint16_t cooldown = 300;
    /*typedef enum TentacleMapping {
      VALVE_T1K = Tle94112Rpi::HalfBridge::TLE_HB3,  VALVE_T1G = Tle94112Rpi::HalfBridge::TLE_HB5,
      VALVE_T2K = Tle94112Rpi::HalfBridge::TLE_HB12, VALVE_T2G = Tle94112Rpi::HalfBridge::TLE_HB8,
      VALVE_T3K = Tle94112Rpi::HalfBridge::TLE_HB2,  VALVE_T3G = Tle94112Rpi::HalfBridge::TLE_HB1,
      VALVE_T4K = Tle94112Rpi::HalfBridge::TLE_HB11, VALVE_T4G = Tle94112Rpi::HalfBridge::TLE_HB7,
      VALVE_T5K = Tle94112Rpi::HalfBridge::TLE_HB10, VALVE_T5G = Tle94112Rpi::HalfBridge::TLE_HB9
    };*/
    Tle94112Rpi::HalfBridge VALVE_T1K = Tle94112Rpi::HalfBridge::TLE_HB3;
    Tle94112Rpi::HalfBridge VALVE_T1G = Tle94112Rpi::HalfBridge::TLE_HB5;
    Tle94112Rpi::HalfBridge VALVE_T2K = Tle94112Rpi::HalfBridge::TLE_HB12;
    Tle94112Rpi::HalfBridge VALVE_T2G = Tle94112Rpi::HalfBridge::TLE_HB8;
    Tle94112Rpi::HalfBridge VALVE_T3K = Tle94112Rpi::HalfBridge::TLE_HB2;
    Tle94112Rpi::HalfBridge VALVE_T3G = Tle94112Rpi::HalfBridge::TLE_HB1;
    Tle94112Rpi::HalfBridge VALVE_T4K = Tle94112Rpi::HalfBridge::TLE_HB11;
    Tle94112Rpi::HalfBridge VALVE_T4G = Tle94112Rpi::HalfBridge::TLE_HB7;
    Tle94112Rpi::HalfBridge VALVE_T5K = Tle94112Rpi::HalfBridge::TLE_HB10;
    Tle94112Rpi::HalfBridge VALVE_T5G = Tle94112Rpi::HalfBridge::TLE_HB9;

    enum Tentacle
    {
      TENTACLE_1 = 0, TENTACLE_2, TENTACLE_3, TENTACLE_4, TENTACLE_5,
      TENTACLE_FRONT, TENTACLE_DIAG_RL, TENTACLE_RIGHT, TENTACLE_LEFT, TENTACLE_DIAG_LR, TENTACLE_BACK,
      TENTACLE_FRONT_BACK, TENTACLES_ALL
    };
    enum TentacleMove
    {
      TENTACLE_LIFT = 0, TENTACLE_CROUCH
    };
    enum TentacleDelays
    {
      /*
      CAREFULLY! tune these parameters - start with small values.
      The longer the delay, the higher the posibility to damage a tentacle!
      CROUCH refers to the small air chamber, LIFT to the big one.
      The number refers to the number of switched tentacles.
      */
      TENTACLE_DELAY_CROUCH_1 = 50, TENTACLE_DELAY_LIFT_1 = 350,
      TENTACLE_DELAY_CROUCH_2 = 80, TENTACLE_DELAY_LIFT_2 = 350,
      TENTACLE_DELAY_CROUCH_3 = 100, TENTACLE_DELAY_LIFT_3 = 400,
      TENTACLE_DELAY_CROUCH_ALL = 200, TENTACLE_DELAY_LIFT_ALL = 450
    };
    void operateHalfBridge(Tle94112Rpi::HalfBridge hb, Tle94112Rpi::HBState state) {
      char message[100];
      sprintf(message, "HB:%d\tSTATE:%d", (int)hb, (int)state);
      log("OPERATE", message);
      controller->configHB(hb, state, Tle94112Rpi::TLE_NOPWM);
    }
    void operateValve(Tle94112Rpi::HalfBridge valve, uint16_t openTime) {
      operateHalfBridge(valve, Tle94112Rpi::TLE_HIGH);
      delay(openTime);
      operateHalfBridge(valve, Tle94112Rpi::TLE_FLOATING);
    };
    void operateValve(Tle94112Rpi::HalfBridge valve1, Tle94112Rpi::HalfBridge valve2, uint16_t openTime) {
      operateHalfBridge(valve1, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(valve2, Tle94112Rpi::TLE_HIGH);
      delay(openTime);
      operateHalfBridge(valve1, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(valve2, Tle94112Rpi::TLE_FLOATING);
    };
    void operateValve(Tle94112Rpi::HalfBridge valve1, Tle94112Rpi::HalfBridge valve2, Tle94112Rpi::HalfBridge valve3, uint16_t openTime) {
      operateHalfBridge(valve1, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(valve2, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(valve3, Tle94112Rpi::TLE_HIGH);
      delay(openTime);
      operateHalfBridge(valve1, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(valve2, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(valve3, Tle94112Rpi::TLE_FLOATING);
    };
    void moveAll(TentacleMove move) {
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T3K : VALVE_T3G, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T4K : VALVE_T4G, Tle94112Rpi::TLE_HIGH);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T5K : VALVE_T5G, Tle94112Rpi::TLE_HIGH);
      delay(move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_ALL : TENTACLE_DELAY_LIFT_ALL);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T3K : VALVE_T3G, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T4K : VALVE_T4G, Tle94112Rpi::TLE_FLOATING);
      operateHalfBridge(move == TENTACLE_CROUCH ? VALVE_T5K : VALVE_T5G, Tle94112Rpi::TLE_FLOATING);
    };
    void stopAll() {
      log("HB STOP", "ALL HBs to FLOATING");
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB1, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB2, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB3, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB4, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB5, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB6, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB7, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB8, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB9, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB10, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB11, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
      controller->configHB(Tle94112Rpi::HalfBridge::TLE_HB12, Tle94112Rpi::TLE_FLOATING, Tle94112Rpi::TLE_NOPWM);
    };
    void moveTentacle(Tentacle tentacle, TentacleMove move) {
      switch(tentacle) {
        case (TENTACLE_1):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_1 : TENTACLE_DELAY_LIFT_1);
          break;
        case (TENTACLE_2):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_1 : TENTACLE_DELAY_LIFT_1);
          break;
        case (TENTACLE_3):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T3K : VALVE_T3G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_1 : TENTACLE_DELAY_LIFT_1);
          break;
        case (TENTACLE_4):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T4K : VALVE_T4G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_1 : TENTACLE_DELAY_LIFT_1);
          break;
        case (TENTACLE_5):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T5K : VALVE_T5G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_1 : TENTACLE_DELAY_LIFT_1);
          break;
        case (TENTACLE_FRONT):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_2 : TENTACLE_DELAY_LIFT_2);
          break;
        case (TENTACLE_DIAG_RL):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, move == TENTACLE_CROUCH ? VALVE_T3K : VALVE_T3G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_2 : TENTACLE_DELAY_LIFT_2);
          break;
        case (TENTACLE_RIGHT):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, move == TENTACLE_CROUCH ? VALVE_T5K : VALVE_T5G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_2 : TENTACLE_DELAY_LIFT_2);
          break;
        case (TENTACLE_LEFT):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, move == TENTACLE_CROUCH ? VALVE_T3K : VALVE_T3G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_2 : TENTACLE_DELAY_LIFT_2);
          break;
        case (TENTACLE_DIAG_LR):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, move == TENTACLE_CROUCH ? VALVE_T5K : VALVE_T5G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_2 : TENTACLE_DELAY_LIFT_2);
          break;
        case (TENTACLE_BACK):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T3K : VALVE_T3G, move == TENTACLE_CROUCH ? VALVE_T5K : VALVE_T5G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_2 : TENTACLE_DELAY_LIFT_2);
          break;
        case (TENTACLE_FRONT_BACK):
          operateValve(move == TENTACLE_CROUCH ? VALVE_T1K : VALVE_T1G, move == TENTACLE_CROUCH ? VALVE_T2K : VALVE_T2G, move == TENTACLE_CROUCH ? VALVE_T4K : VALVE_T4G, move == TENTACLE_CROUCH ? TENTACLE_DELAY_CROUCH_3 : TENTACLE_DELAY_LIFT_3);
          break;
        case (TENTACLES_ALL):
          moveAll(move);
          break;
      }
      log("COOLDOWN", "WAITING");
      delay(cooldown);
    };
};

int main(int argc, char const *argv[])
{
  log("MAIN", "Initializing Half Bridge Controller...");
  Tle94112Rpi controller;
  controller.begin();

  // Clear all errors to start clean
  controller.clearErrors();

  // Initialize Octocat
  log("MAIN", "Octocat start...");
  Octocat oc(controller);
  
  // Octocat loop
  while (1) {
    
    // Front/back movement
    for (uint8_t i = 0; i < 3; i++) {
      oc.moveTentacle(oc.TENTACLE_FRONT_BACK, oc.TENTACLE_CROUCH);
      oc.moveTentacle(oc.TENTACLE_FRONT_BACK, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_BACK, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_BACK, oc.TENTACLE_CROUCH);
    }

    // Round movement
    for (uint8_t i = 0; i < 2; i++) {
      oc.moveTentacle(oc.TENTACLE_1, oc.TENTACLE_CROUCH);
      oc.moveTentacle(oc.TENTACLE_1, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_2, oc.TENTACLE_CROUCH);
      oc.moveTentacle(oc.TENTACLE_3, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_4, oc.TENTACLE_CROUCH);
      oc.moveTentacle(oc.TENTACLE_4, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_5, oc.TENTACLE_CROUCH);
      oc.moveTentacle(oc.TENTACLE_5, oc.TENTACLE_LIFT);
    }

    // Side movement
    for (uint8_t i = 0; i < 2; i++) {
      oc.moveTentacle(oc.TENTACLE_LEFT, oc.TENTACLE_CROUCH);
      oc.moveTentacle(oc.TENTACLE_LEFT, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_RIGHT, oc.TENTACLE_LIFT);
      oc.moveTentacle(oc.TENTACLE_RIGHT, oc.TENTACLE_CROUCH);
    }

    // Make sure to have all valves closed at end
    oc.stopAll();

    log("MAIN", "Waiting for movement interval...");
    delay(MOVEMENT_INTERVAL);
  }

  // Make sure to have all valves closed at end
  oc.stopAll();
}

Credits

Infineon Team

Infineon Team

75 projects • 116 followers

Comments