Перчатка Mark gauntlet v4.2

В данной статье я постараюсь изложить суть моего проекта и показать процесс, который из наброска робота-собаки перетёк в заказ печатных плат для перчатки

Начало

Перчатка вытекла прямиком из моего проекта Mark, кроме того она является его значимой частью, так что начать следует с него.

Самый первый прототип робота был сделан в один из вечеров лета 2018 года. Это был четвероногий робот, состоящий из 8 сервоприводов SG90 (обычных синих) и кусков гвоздей. Соединялось всё это термоклеем и не имело ни единого шанса на нормальную работу ввиду очень неудачного распределения массы. Но я этого не знал и в тот же вечер заставил его шагать по прямой, а ещё через минут 15 после этого плата, через которую шло питание, задымилась и на столе оказался отпаявшийся линейный стабилизатор (к слову я так и не понял что там произошло).

Починить эту горку термоклея гвоздей и изоленты я так и не смог. В своё оправдание могу сказать, что в тот момент я не умел паять, из электроники понимал только что нельзя замыкать + и -, а о существовании 3D печати и не слышал.

В конце лета заказал себе первый принтер — Anet A8.

2a5429e735e84c326155ae598280fdc8

Обычный принтер для ознакомления с технологией: рама из акрила, кинематика с «дрыгостолом» и шумные моторы (скорее их драйвера)

Почти сразу после его покупки я освоил tinkercad, где и воссоздал того робота на 4 ногах уже с заменой гвоздей на пластик и добавлением поворотного сервопривода.

Данное творение так и не заходило, но сподвигло меня на создание других версий. Возможно для моих червероногих роботов сделаю отдельную статью, так что просто дам последовательность из фотографий версий.

800adf91fbdf07eadef335fde6d5fe70.jpgcb79e68a458e3924882908ae963b2709.JPG4283bad14bb2a70650d1c42de546593c.JPG708e398bbe6d93156da61f5cf62ea71a

Последняя версия сейчас обзаводится корпусом, но уже нормально ходила и имеет неплохую грузоподъёмность.

С последней и предпоследней версией я победил на 2 мероприятиях и решил расширять серию Mark. Именно так на скорую руку я записал относительно нереальные планы на роботов, включая большие металлические базы для роботов. Но затем я всё же переосмыслил идею серии — можно же сделать реально интересную систему марсоходов, которая может себя показать и на Земле.

Собственно вот как я пока что это позиционирую:

Система роботов Mark - это исследовательский комплекс для автономного исследования местности, в частности — поверхности Марса.​

Mark 6 - основная база, предназначен для защиты остальных роботов от неблагоприятных условий.​

Mark 3 — основной разведчик, благодаря ногам может взбираться на уступы,  также имеет 4 колеса.​

Mark 4 — шнекоход, также выполняет роль спасательного аппарата.  ​

Mark 5 - инсектоид с крыльями и 6 ногами. Может использоваться для изучения очень узких проходов.​

Mark 7 - робозмея, также как и Mark 5 может исследовать узкие проходы и отверстия.​

Mark gauntlet — перчатка для ручного управления всеми роботами.​​

Из представленных роботов у меня есть почти готовые Mark 6, Mark 4, ну и собственно Mark 3 и Mark gauntlet.

Из интересного по ним пока есть только основа Mark 6 и его шасси, которые пока печатаются 

f76c0ef6f1428282e5583b482d224d22a3d7deea1fd00006dd6ea8f5b2b73ed7.PNG

Разработка перчатки: версия 1

Первая версия перчатки была сделана весной 2020 года и сразу заработала с тестовым стендом, но там мало что могло не сработать: я использовал обычный радиомодуль на 433 МГц с антенной из куска провода. Более подробно там есть в видео (моё первое видео, так что там всё очень посредственно) https://youtu.be/eEAHhr9Suug? t=194

0137e3156cb514b1eb0940d86d794aee.PNG

Разработка перчатки: версия 2

Вторая версия была уже через 2 недели, так как она являлась прямым продолжением первой почти во всём.

592e34b5a74a2eecc09d257192e96ccb.jpg

Тут уже был радиомодуль nrf24l01, несколько режимов работы и выбор канала передачи. На работу перчатки можно глянуть в видео https://youtu.be/P_fq7KkfJrI

Кроме того я решил пойти с этой версией на фестиваль Rukami. С этого момента перчатка уже стала основным направлением работ на 2–3 месяца, что выдало в итоге неплохой результат.

Разработка перчатки: версии 3 и 4

Обе имеют схожий функционал и были сделаны каждая за пару дней.

3 версия:

daede65eef17d467ab849b808e5855b5.jpg

Функционал:

  • WiFi модуль esp8266

  • Радиомодуль NRF24l01+

  • Мини радиомодуль на 433 МГц

  • Bluetooth модуль

  • Акселерометр + гироскоп на перчатке

  • Панель управления с OLED дисплеем

В целом получилась нормальная версия, но её было бы сложно повторять из-за пайки навесом прямо на корпусе. Вот подобие описания этой версии https://youtu.be/52WvejA6dyk .

4 версия:

Тут уже я взял всё что подходило под концепцию и добавил к этому контроллер Atmega2560

535e6726b8cb534af077f79f78968c2f.jpg

Видео с процессом её создания:

Функционал:

  • WiFi модуль

  • Радиомодуль NRF24L01+

  • Радиомодуль LoRa

  • MP3 плеер и динамик к нему

  • ИК- светодиод (для простейшей связи)

  • Мощные адресные светодиоды сбоку

  • Акселерометр+гироскоп

  • Датчик цвета + жестов

  • Панель управления с OLED дисплеем

На этом можно было бы и остановиться, но я решил пойти дальше и сделать версию 4.2

Версия 4.2 или завершающий штрих перчатки

Про уже спроектированные части я расскажу подробно, но платы пока ещё не пришли, так что сборку и результат уже покажу в следующей статье

Основа возвращается с первой версии из-за подходящей геометрии

f3c69604e36e281f2af6b9f198dbe0a5.jpg

Перчатка скорее всего останется с версии 4

5984a0fd4a17cf975833791b290be495.PNG

Для питания будут использоваться 3 аккумулятора 18650 на 3.4 А*ч каждый, что обеспечит достаточно большую автономность. Крепиться это будет на плечо.

da00e945de8eb60ec49ffefa4257e398.PNG

Почти вся электроника будет распаяна на 2 печатные платы, которые соединятся вместе

87fe1484e46098db33e708ca8d1cb640.jpg

Ну и первоначальный код, который будет использоваться для теста на работоспособность. В нём я не использовал пока только LoRa модуль. Ссылка на гитхаб: https://github.com/Madjogger1202/Mark_GauntletV4.2/blob/main/src/main.cpp

Дальнейшее создание этой версии будет уже в ближайшее время.

/*
  Hi stranger, this is main code file for this project
  I'm not a 100% programmer, but i can make electronics work,
  so i will be grateful if you add any features

  it is fully opensource project, so anyone can build stuff based on this code 

  have a great time reading this badly written working code (^_^) 

*/

#include       // why not...
#include 
#include 
// i have to make all modules work, so i will use some libraris to make life easier
//1) Display.      im using 0.96 oled from china, it is not standart at dimentions, bt i like how it looks in final designs :)
#include 
#include  // Adafruit librari works 50/50, it depends on display driver (yes, they can hava same names, bt diffrent drivers)

//2) RGB Led panel.       LEDs 2812 (8-bit panel) 
#include 

//3) NRF24L01+ 
#include 
#include 

//4)APDC9960 usefull sensor
#include "Adafruit_APDS9960.h"

//5) LoRa radio sx1278
#include 

//6) MPU6050 gyro + acsel
#include 
#include 

//7) MP3 module
#include 

// first switches connection
int8_t first_sw[8] = { A14, A13, A12, A11, A10, A9, A8, A7 };

// second switches connection
int8_t second_sw[8] = { 38, 37, 36, 35, 34, A6, 32, A15 };

// buttons connection
int8_t buttons[4] = { A3, A1, A0, A2 };

#define LED1 10
#define LED2 11

#define JOY_X A6
#define JOY_Y A5

#define POT A4

#define LORA_D0 42
#define LORA_NSS 43
#define LORA_RST 44

#define NRF_CSN 40
#define NRF_CE 41

#define IR_LED 7
#define R_LED 4
#define G_LED 5
#define B_LED 6

#define WS_LED 45


LEDdata leds[8];
microLED strip(leds, 8, WS_LED); 
#define ORDER_GRB 

RF24 radio(NRF_CE, NRF_CSN);

Adafruit_MPU6050 mpu;

Adafruit_SSD1306 display(128, 32, &Wire, -1);

Adafruit_APDS9960 apds;

volatile bool irqMPU;
volatile bool irqAPDC;

struct allData
{
  volatile boolean irqMPU;
  volatile boolean irqAPDC;

  bool stable;
  int8_t x_acs;
  int8_t y_acs;
  int8_t z_acs;

  uint8_t mode;
  uint8_t channel;

  uint16_t button;
  
  uint16_t potData;
  uint16_t joyX;
  uint16_t joyY;

  uint8_t led1Mode;
  uint8_t led2Mode;

  uint8_t redLedMode;
  uint8_t blueLedMode;
  uint8_t greenLedMode;

  uint8_t wsLedMode;

  

}mainData;

struct radioData
{
  bool stable;
  int8_t x_acs;
  int8_t y_acs;
  int8_t z_acs;

  uint8_t mode;
  uint8_t channel;

  uint16_t button;
  
  uint16_t potData;
  uint16_t joyX;
  uint16_t joyY;

} telemetriData;

void readMode();
void readCh();
void readAcs();
void readJoy();
void readPot();
void readButtons();
void sendNRF();
void sendBL();
void sendLoRa();   // will reliase it soon
void displayInfo();


// at all it is possible to create up to 256 diffrent modes,
// but if you need more - connect mode counter with channel counter (maybe partly)
void n1Mode();
void n2Mode();
void n3Mode();
void n4Mode();
void n5Mode();
void n6Mode();
void n7Mode();
void n8Mode();
void n9Mode();
void n10Mode();
void n11Mode();
void n12Mode();



void acsel()
{
  mainData.irqMPU=true;
}
void gesture()
{
  mainData.irqAPDC=true;
}

void setup() 
{
  for(int i=0;i<8;i++)
    pinMode(first_sw[i], INPUT_PULLUP);
  for(int i=0;i<8;i++)
    pinMode(second_sw[i], INPUT_PULLUP);
  for(int i=0;i<4;i++)
    pinMode(buttons[i], INPUT_PULLUP);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  analogWrite(LED1, 10);
  analogWrite(LED2, 100);
  
  pinMode(JOY_X, INPUT);
  pinMode(JOY_Y, INPUT);

  pinMode(POT, INPUT_PULLUP);
  
  pinMode(LORA_D0, OUTPUT);
  pinMode(LORA_NSS, OUTPUT);
  pinMode(LORA_RST, OUTPUT);
  
  pinMode(NRF_CSN, OUTPUT);
  pinMode(NRF_CE, OUTPUT);
  
  pinMode(IR_LED, OUTPUT);
  pinMode(R_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(B_LED, OUTPUT);
  
  pinMode(WS_LED, OUTPUT);

  strip.setBrightness(130);  
  strip.clear();
  strip.show(); 
  strip.fill(mCOLOR(YELLOW));
  strip.show();
  Serial.begin(115200);
  Serial2.begin(9600);
  mp3_set_serial(Serial2);
  mp3_set_volume(30);
  mp3_play (1);
  if (!mpu.begin())
    Serial.println("Sensor init failed");
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.display();
  display.clearDisplay();
  
  display.display();
  if(!apds.begin())
    Serial.println("failed to initialize device! Please check your wiring.");
  apds.enableProximity(true);
  apds.enableGesture(true);
  radio.begin();                                      
  radio.setChannel(100);                               
  radio.setDataRate     (RF24_1MBPS);                   
  radio.setPALevel      (RF24_PA_HIGH);                 
  radio.openWritingPipe (0x1234567899LL);               
  radio.setAutoAck(false);

  attachInterrupt(0, acsel, RISING);
  attachInterrupt(1, gesture, RISING);

  Serial1.begin(9600);         // bluetooth module connected to Serial1 
  delay(5000);
  mp3_stop ();
  
  
}

void loop()
{
 readMode();
 readCh();
 readAcs();
 readJoy();
 readPot();
 readButtons();
 Serial.println(digitalRead(A14));
 Serial.println(digitalRead(A13));
 Serial.println(digitalRead(A12));
 Serial.println(digitalRead(A11));
 Serial.println(digitalRead(A10));
 Serial.println(digitalRead(A9));
 Serial.println(digitalRead(A8));
 Serial.println(digitalRead(A7));
 Serial.println();
 Serial.println();
 
 
 displayInfo();

  switch (mainData.mode)
  {
  case 0:
    n1Mode();
    break;
  case 2:
    n2Mode();
    break;
  case 3:
    n3Mode();
    break;
  case 4:
    n4Mode();
    break;
  
  }
}


void readAcs()      // reading acseleration values from sensor directly to main struct
{
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  mainData.x_acs = a.acceleration.x;
  mainData.y_acs = a.acceleration.y;
  mainData.z_acs = a.acceleration.z;
  return;
}

void readJoy()     // i am filering analog values for better perfomance 
{
  mainData.joyX = (analogRead(JOY_X)+analogRead(JOY_X)+analogRead(JOY_X)+analogRead(JOY_X))/4;
  mainData.joyY = (analogRead(JOY_Y)+analogRead(JOY_Y)+analogRead(JOY_Y)+analogRead(JOY_Y))/4;
  return;
}

void readPot()
{
  mainData.potData = analogRead(POT);
  return;
}

void readButtons()   // buttons : 1) 1; 2)0; 3)1; 4)1;   and mainData.button == 1011 
{
  mainData.button = !digitalRead(A1)*1000+!digitalRead(A2)*100+!digitalRead(A3)*10+!digitalRead(A0);
  return;
}

void sendNRF()
{
  // i am writing telemetri struct only when sending data
  // in this case i can track how relevant telemetri data is

  telemetriData.stable = mainData.stable;
  telemetriData.x_acs = mainData.x_acs;
  telemetriData.y_acs = mainData.y_acs;
  telemetriData.z_acs = mainData.z_acs;

  telemetriData.mode = mainData.mode;
  telemetriData.channel = mainData.channel;

  telemetriData.button = mainData.button;
  
  telemetriData.potData = mainData.potData;
  telemetriData.joyX = mainData.joyX;
  telemetriData.joyY = mainData.joyY;
  radio.write(&telemetriData, sizeof(telemetriData));
}

void sendBL(String inp)
{
  Serial1.print(inp);
  return;
}


// void sendLoRa();

void displayInfo()
{
  display.clearDisplay();
  display.setTextSize(1);             
  display.setTextColor(WHITE);       
  display.setCursor(0, 0);            
  display.print(mainData.channel);    
  display.print("  ");          
  display.print(mainData.mode);
  display.print("  ");
  display.println(mainData.z_acs);      
  display.print(mainData.button);
  display.print("  ");
  display.print(mainData.joyX);
  display.print("  ");
  display.print(mainData.joyX);
  display.print("  ");
  display.println(mainData.potData);
  display.display();
}


void readMode()
{
  bitWrite(mainData.mode, 0, (!digitalRead(A14)));
  bitWrite(mainData.mode, 1, (!digitalRead(A13)));
  bitWrite(mainData.mode, 2, (!digitalRead(A12)));
  bitWrite(mainData.mode, 3, (!digitalRead(A11)));
  bitWrite(mainData.mode, 4, (!digitalRead(A10)));
  bitWrite(mainData.mode, 5, (!digitalRead(A9)));
  bitWrite(mainData.mode, 6, (!digitalRead(A8)));
  bitWrite(mainData.mode, 7, (!digitalRead(A7)));
  return;
}

void readCh()
{
  bitWrite(mainData.channel, 0, digitalRead(second_sw[0]));
  bitWrite(mainData.channel, 1, digitalRead(second_sw[1]));
  bitWrite(mainData.channel, 2, digitalRead(second_sw[2]));
  bitWrite(mainData.channel, 3, digitalRead(second_sw[3]));

  bitWrite(mainData.channel, 4, digitalRead(second_sw[4]));
  bitWrite(mainData.channel, 5, digitalRead(second_sw[5]));
  bitWrite(mainData.channel, 6, digitalRead(second_sw[6]));
  bitWrite(mainData.channel, 7, digitalRead(second_sw[7]));
  return;
}


void n1Mode()
{
  sendNRF();
  digitalWrite(LED1, !digitalRead(LED1)); // just blink to understand, that it is working
}
void n2Mode()
{

}
void n3Mode()
{

}
void n4Mode()
{

}
void n5Mode()
{

}
void n6Mode()
{

}
void n7Mode()
{

}
void n8Mode()
{

}
void n9Mode()
{

}
void n10Mode()
{

}
void n11Mode()
{

}
void n12Mode()
{

}

© Habrahabr.ru