Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Marcus Eliasson
Published © CC BY-SA

Crazycar

Use your Crazyflie 2.0 to control a Skeleton bot

IntermediateFull instructions provided2 hours5,137
Crazycar

Things used in this project

Hardware components

Crazyflie 2.0
Bitcraze Crazyflie 2.0
×1
Prototyping deck
Bitcraze Prototyping deck
×1
Seeed Studio Skeleton Bot - 4WD Hercules Mobile Robotic Platform
×1
Seeed Studio Grove - Universal 4 Pin Buckled 20cm Cable
×1
Seeed Studio Grove - Universal 4 pin connector 90°
×1

Software apps and online services

Arduino IDE
Arduino IDE
Bitcraze VM
Bitcraze VM

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Crazycar deck schematic

Connect the Groove connector on the prototyping board according to the following schematic.

Code

Crazycar deck source

C/C++
The source file for the Crazycar deck.

Add this to the build by adding the following to the Makefile:
PROJ_OBJ_CF2 += crazycar.o
CFLAGS += -DDECK_FORCE=bcCrazycar
/**
 *    ||          ____  _ __
 * +------+      / __ )(_) /_______________ _____  ___
 * | 0xBC |     / __  / / __/ ___/ ___/ __ `/_  / / _ \
 * +------+    / /_/ / / /_/ /__/ /  / /_/ / / /_/  __/
 *  ||  ||    /_____/_/\__/\___/_/   \__,_/ /___/\___/
 *
 * Crazyflie control firmware
 *
 * Copyright (C) 2016 Bitcraze AB
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, in version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * crazycar.c - Deck driver for the Crazyflie 2.0 Crazycar deck
 */

#include <stdint.h>
#include <stdlib.h>
#include "stm32fxxx.h"

#include "deck.h"

#include "FreeRTOS.h"
#include "timers.h"
#include "uart2.h"
#include "debug.h"
#include "log.h"

static int logIdRoll;
static int logIdPitch;

/* Template data for controlling the Skeleton bot */
static char data[] = {'S', 'S', '0', '0', 0x0A};

/* Create output string for sending to the Skeleton bot */
void carSetControl(float roll, float pitch)
{
  float f = pitch / 30.0;
  float t = roll / 60.0;

  float m1 = f + t;
  float m2 = f - t;

  if (m1 > 1.0)
    m1 = 1.0;
  if (m1 < -1)
    m1 = -1;

  if (m2 > 1.0)
    m2 = 1.0;
  if (m2 < -1)
    m2 = -1;

  if (m1 > 0)
  {
    data[0] = 'F';
    data[2] = (int)(m1 * 10) + '0';
  } else {
    data[0] = 'B';
    data[2] = (int)(m1 * -10) + '0';
  }

  if (m2 > 0)
  {
    data[1] = 'F';
    data[3] = (int)(m2 * 10) + '0';
  } else {
    data[1] = 'B';
    data[3] = (int)(m2 * -10) + '0';
  }
}


/* Send commands to Skeleton bot at 10Hz */
static xTimerHandle timer;
static void ctrlTimer(xTimerHandle timer)
{
    carSetControl(logGetFloat(logIdRoll), logGetFloat(logIdPitch));
    uart2SendData(sizeof(data), (uint8_t*)data);
}

/* Initialize the deck driver */
static void crazycarDeckInit(DeckInfo *info)
{
    logIdRoll = logGetVarId("ctrltarget", "roll");
    logIdPitch = logGetVarId("ctrltarget", "pitch");

    uart2Init(19200);
    timer = xTimerCreate( "ctrlTimer", M2T(100),
                           pdTRUE, NULL, ctrlTimer );
    xTimerStart(timer, 100);
}

static const DeckDriver crazycar_deck = {
  .vid = 0xBC,
  .pid = 0x00,
  .name = "bcCrazycar",

  .usedPeriph = DECK_USING_UART2,
  .usedGpio = DECK_USING_TX2 | DECK_USING_RX2,

  .init = crazycarDeckInit
};

DECK_DRIVER(crazycar_deck);

Skeleton bot Arduino code

Arduino
Code that should be loaded onto the Skeleton bot Arduino
// pin ctrl
#define PINCS           6           // all mos cs
#define PINM1R          4
#define PINM1F          5
#define PINM2F          7
#define PINM2R          8
#define PINPWMA         9           // PWM channel A (motor A speed)
#define PINPWMB         10          // PWM channel B (motor B speed)

String txtMsg = "";
char s;
int motorSpeed = 0;

void setup()
{
    Serial.begin(19200);
    Serial.println("HERCULES 4WD TEST");

    pinMode(PINCS, OUTPUT);
    pinMode(PINM1F, OUTPUT);
    pinMode(PINM1R, OUTPUT);
    pinMode(PINM2F, OUTPUT);
    pinMode(PINM2R, OUTPUT);

    motorSetSpeed(255);
}


void loop()
{
    while (Serial.available() > 0)
    {
        s = (char)Serial.read();
        if (s == '\n')
        {
            Serial.print("Command: ");
            Serial.print(txtMsg);

            Serial.print(" Char: ");
            char charBuf[5];
            txtMsg.toCharArray(charBuf, 5);
            Serial.print(charBuf);
            
            Serial.print(" SpeedA: ");
            int speedA = charBuf[2];
            speedA = ( speedA - 48 ) * 28;
            Serial.print( speedA );
            
            Serial.print(" SpeedB: ");
            int speedB = charBuf[3];
            speedB = (speedB - 48) * 28;
            Serial.print( speedB );    
      
            analogWrite(PINPWMA, speedA);
            analogWrite(PINPWMB, speedB);      

            if ( charBuf[0] == 'S' && charBuf[1] == 'S')
            {
                motorStop(0);
                Serial.print(" Action: Stop");
            }

            if ( charBuf[0] == 'F' && charBuf[1] == 'F')
            {
                motorForward(0);
                Serial.print(" Action: Forward");
            }

            if ( charBuf[0] == 'B' && charBuf[1] == 'B')
            {
                motorReverse(0);
                Serial.print(" Action: Reverse");
            }

            if ( charBuf[0] == 'B' && charBuf[1] == 'F')
            {
                motorTurnLeft(0);
                Serial.print(" Action: Left");
            }

            if ( charBuf[0] == 'F' && charBuf[1] == 'B')
            {
                motorTurnRight(0);
                Serial.print(" Action: Right");
            }

            Serial.println(";");
            txtMsg = "";
        }
        else
        {
            txtMsg += s;
        }
    }
}


void motorSetSpeed(int power)
{
    motorSpeed = power;
    analogWrite(PINPWMA, motorSpeed);
    analogWrite(PINPWMB, motorSpeed);
}

void motorStop(int duration)
{
    digitalWrite(PINCS, LOW);
    digitalWrite(PINM1F, LOW);

    digitalWrite(PINM1R, LOW);
    digitalWrite(PINM2F, LOW);

    digitalWrite(PINM2R, LOW);
    delay(duration);
}

void motorForward(int duration)
{
    digitalWrite(PINM1R, HIGH);
    digitalWrite(PINM1F, LOW);

    digitalWrite(PINM2R, HIGH);
    digitalWrite(PINM2F, LOW);

    digitalWrite(PINCS, HIGH);
    delay(duration);
}

void motorReverse(int duration)
{
    digitalWrite(PINM1R, LOW);
    digitalWrite(PINM1F, HIGH);

    digitalWrite(PINM2R, LOW);
    digitalWrite(PINM2F, HIGH);

    digitalWrite(PINCS, HIGH);
    delay(duration);
}

void motorTurnLeft(int duration)
{
    digitalWrite(PINM1R, LOW);
    digitalWrite(PINM1F, HIGH);

    digitalWrite(PINM2R, HIGH);
    digitalWrite(PINM2F, LOW);

    digitalWrite(PINCS, HIGH);
    delay(duration);
}


void motorTurnRight(int duration)
{
    digitalWrite(PINM1R, HIGH);
    digitalWrite(PINM1F, LOW);

    digitalWrite(PINM2R, LOW);
    digitalWrite(PINM2F, HIGH);

    digitalWrite(PINCS, HIGH);
    delay(duration);
}

crazyflie-firmware

The main Crazyflie 2.0 firmware

Credits

Marcus Eliasson

Marcus Eliasson

2 projects • 12 followers

Comments