В наличии нашел ESP NODE MCU v.3, джойстик HW-504(крайне отвратное устройство-конечная половина хода по всем осям просто не изменяет сопротивления, может кто дать совет по нему-доработать переделать),движки со встроенным редуктором с колесами,два двоййных H-моста на L9110, АЦП ADS1015(так-как на ESP только один АЦП), питание от двух 14500 Li-ion.
с наскока колесную машину с танковой схемой не нашел, поэтому ее и буду делать.
Поворотных колес нет, поворот осуществляется за счет разнонаправленного движения боковых колес относительно друг друга.
Скорость вращения колес меняется ШИМом с ESP.
в качестве шасси металлический конструктор моего детства, единственно дырочки под крепления редукторов надо надфилем чуток по ,5мм проточить, строительные перфорированные пластины подходят под конструктор идеально.
Прикрутил модули на М3 через Festo трубочки.
Как-то вышло
при проверке вращения последнего двигателя задымил ключик в одном плече H-моста, спасибо Джек Ма, ладно, они мне серно не нравились(у них входы управления подтяянуты к + 10К резисторами в моем случае, с ними аккуратней проверяйте напряжение на них при вашем источнике питания, у меня при 2 последовательных LI было 2.9В).
Ставлю MX1508(по названию в инете, хотя в реале у меня стоят MX1616 1035H, datasheet на нее не нашел, поделитесь кто видел), у нее нет подтяжки к +, не надо инвертировать ШИМ и крутить ум.
Накидал проводки на пульт, пока так, пока все так.
Вышло очень даже макетно
Связь плат с помощью протокола ESP-NOW по mac адресам.
код на arduino ide, библиотеки все почти стандартные, накидал из того что было.
код для пульта
- Код: Выделить всё • Развернуть
#include <ESP8266WiFi.h>
#include <espnow.h>
// ЗАМЕНИТЕ МАС-АДРЕС платы, на которую отправляем данные.
uint8_t broadcastAddress[] = {0xF4, 0xCF, 0xA2, 0xD7, 0xC6, 0x91};
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;
// Вводим переменные для хранения отправляемых данных
int16_t mot1p, mot1n, mot2p, mot2n, mot3p, mot3n, mot4p, mot4n;
const long interval = 100;// Обновляем показания датчика каждые 1 секунд
unsigned long previousMillis = 0; // время последнего обновления
String success;// Переменная для хранения состояния отправки
//Пример структуры для отправки
//Должна совпадать со структурой на плате-приемнике
struct struct_message {
int16_t mot1p;
int16_t mot1n;
int16_t mot2p;
int16_t mot2n;
int16_t mot3p;
int16_t mot3n;
int16_t mot4p;
int16_t mot4n;
};
// Создаем переменную для хранения отправляемого сообщения
struct_message driveReadings;
int16_t adc0, adc1;
int16_t a0, a1, a2, a3;
int16_t aa0, aa1, aa2, aa3;
uint8_t v_x_min = 60;
uint8_t v_y_min = 50;
uint8_t v_x_max = 255;
uint8_t v_y_max = 150;
// определяем callback-функцию, которая выводит в монитор порта информацию о
//состоянии отправки. Если функция возвращает 0 – сообщение успешно доставлено
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
// Serial.print("Last Packet Send Status: ");
if (sendStatus == 0) {
// Serial.println("удачно");
}
else {
// Serial.println("fail");
}
}
void getReadings() {
adc0 = ads.readADC_SingleEnded(0); //ось Х вперед-назад
if (580 < adc0 ) {
a0 = map(adc0, 569, 1103, v_x_min, v_x_max);
a1 = 0;
}
else if (adc0 < 560) {
a1 = map(adc0, 1, 568, v_x_max, v_x_min);
a0 = 0;
}
else if ( 560 < adc0 && adc0 < 580 ) {
a0 = 0;
a1 = 0;
}
adc1 = ads.readADC_SingleEnded(1); // ось Y право-лево
if (560 < adc1 ) {
a3 = map(adc1, 552, 1103, v_y_min, v_y_max);
a2 = 0;
}
else if (adc1 < 545) {
a2 = map(adc1, 1, 552, v_y_max, v_y_min);
a3 = 0;
}
else if ( 545 < adc1 && adc1 < 560 ) {
a2 = 0;
a3 = 0;
}
mot1p = a0 + a3;
mot1n = a1+a2;
mot2p = a0 + a2;
mot2n = a1+a3;
mot3p = a0 + a3;
mot3n = a1+a2;
mot4p = a0 + a2;
mot4n = a1+a3;
Serial.print(adc0);
Serial.print(" a0="); Serial.print(a0); Serial.print(" a1="); Serial.print(a1);
Serial.print(" "); Serial.print(adc1);
Serial.print(" a2="); Serial.print(a2); Serial.print(" a3="); Serial.print(a3);
Serial.print(" aa0="); Serial.print(aa0); Serial.print(" aa2="); Serial.print(aa2);
// delay(100);
// digitalWrite(mot, 1);
// delay(1000);
}
void setup() {
Serial.begin(115200);
ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
if (!ads.begin()) {
Serial.println("Failed to initialize ADS.");
while (1);
}
analogWriteRange(255);// разрядность шим
// Выставляем режим работы Wi-Fi
WiFi.mode(WIFI_STA);
WiFi.disconnect();
// Инициализируем протокол ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Указываем роль платы в сети
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
// Регистрируем callback-функцию для получения статуса отправки
esp_now_register_send_cb(OnDataSent);
// Регистрируем пиры
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Сохраняем время последнего обновления показаний
previousMillis = currentMillis;
Serial.print(" mot1p "); Serial.print(driveReadings.mot1p);
Serial.print(" mot1n "); Serial.print(driveReadings.mot1n);
Serial.print(" mot2p "); Serial.print(driveReadings.mot2p);
Serial.print(" mot2n "); Serial.println(driveReadings.mot2n);
//Запрашиваем показания датчика
getReadings();
//Записываем их в переменные
driveReadings.mot1p = mot1p;
driveReadings.mot1n = mot1n;
driveReadings.mot2p = mot2p;
driveReadings.mot2n = mot2n;
driveReadings.mot3p = mot3p;
driveReadings.mot3n = mot3n;
driveReadings.mot4p = mot4p;
driveReadings.mot4n = mot4n;
// Отправляем сообщение
esp_now_send(broadcastAddress, (uint8_t *) &driveReadings, sizeof(driveReadings));
}
}
код для машины
- Код: Выделить всё • Развернуть
#include <ESP8266WiFi.h>
#include <espnow.h>
// ЗАМЕНИТЕ МАС-АДРЕС платы, на которую отправляем данные.
uint8_t broadcastAddress[] = {0x58, 0xBF, 0x25, 0xD7, 0x53, 0x07};
int16_t m1p = D1;
int16_t m1n = D2;
int16_t m2p = D3;
int16_t m2n = D4;
int16_t m3p = D6;
int16_t m3n = D5;
int16_t m4p = D8;
int16_t m4n = D7;
// Вводим переменные для хранения принимаемых данных
int16_t mot1p, mot1n, mot2p, mot2n, mot3p, mot3n, mot4p, mot4n;
// Обновляем показания датчика каждые 1 секунд
const long interval = 100;
unsigned long previousMillis = 0; // время последнего обновления
// Переменная для хранения состояния отправки
String success;
//Пример структуры для отправки
//Должна совпадать со структурой на плате-приемнике
typedef struct struct_message {
int16_t mot1p;
int16_t mot1n;
int16_t mot2p;
int16_t mot2n;
int16_t mot3p;
int16_t mot3n;
int16_t mot4p;
int16_t mot4n;
} ;
// Создаем переменную для хранения отправляемого сообщения
// То же, но для принимаемого сообщения
struct_message incomingReadings;
// определяем callback-функцию, которая выводит в монитор порта информацию о
//состоянии отправки. Если функция возвращает 0 – сообщение успешно доставлено
// То же, для индикации состояния приема данных
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
Serial.print("Bytes received: ");
Serial.print(len);
mot1p = incomingReadings.mot1p;
mot1n = incomingReadings.mot1n;
mot2p = incomingReadings.mot2p;
mot2n = incomingReadings.mot2n;
mot3p = incomingReadings.mot3p;
mot3n = incomingReadings.mot3n;
mot4p = incomingReadings.mot4p;
mot4n = incomingReadings.mot4n;
}
void printIncomingReadings(){
// Отображаем показания в мониторе порта
//Serial.print(mot1p);Serial.print(" ");Serial.print(mot1n); Serial.print(incomingReadings.mot1p);
}
void setup(){
// Запускаем монитор порта
Serial.begin(115200);
analogWriteRange(255);// разрядность шим
analogWriteFreq(300); //analogWriteFreq(100.. 40000 Гц) на высокой частоте хуже запускаются двигатели с низкой скорости
// Выставляем режим работы Wi-Fi
WiFi.mode(WIFI_STA);
WiFi.disconnect();
// Инициализируем протокол ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Указываем роль платы в сети
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
// Регистрируем callback-функцию для получения статуса приема
esp_now_register_recv_cb(OnDataRecv);
}
void loop(){
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Сохраняем время последнего обновления показаний
previousMillis = currentMillis;
// Выводим входящие данные
printIncomingReadings();
Serial.print("mot1p ");Serial.print(mot1p);
Serial.print(" mot1n ");Serial.print(mot1n);
Serial.print("mot2p ");Serial.print(mot2p);
Serial.print(" mot2n ");Serial.print(mot2n);
Serial.print("mot3p ");Serial.print(mot3p);
Serial.print(" mot3n ");Serial.print(mot3n);
Serial.print("mot4p ");Serial.print(mot4p);
Serial.print(" mot4n ");Serial.println(mot4n);
}
analogWrite(m1p,mot1p);
analogWrite(m1n,mot1n);
analogWrite(m2p,mot2p);
analogWrite(m2n,mot2n);
analogWrite(m3p,mot3p);
analogWrite(m3n,mot3n);
analogWrite(m4p,mot4p);
analogWrite(m4n,mot4n);
}
пришлось частоту шима сделать 300Гц, минимальное заполнение шим при котором двигатели начинают крутиться 50 из 255.
При частоте ШИМ 5кГц(еле пищит) стартуют 130 из техже 255.
При частоте ШИМ 15кГц(тихо) стартуют 150 из техже 255.
Хотел узнать что за запрет(взято с интернета) использования в ESP NODE MCU v.3 пина D0(GPIO16) как ШИМ. Я по незнанке им регулировал св.диод все вроде работало, потом после более детального ознакомления с ESP прочитал про запрет, но никто не объясняет почему.