Jan Ingo Haller и Lorin Samija в рамках семинара по вычислительному дизайну и цифровому производству в магистерской программе «Интеграционные технологии и исследования архитектурного дизайна» (ITECH) в Штутгартском университете создали необычного робота-питомца, которого назвали mOLOID.
mOLOID (moving OLOID) — двигается очень необычным образом. Когда внутреннее устройство робота спрятано под тканевым покрытием, то кажется, что робот сам собой перекатывается, словно какое-то непонятное существо.
В основе этого необычного робота-питомца лежит оригинальный геометрический объект — олоид.
Олоид — трёхмерный криволинейный геометрический объект, открытый Paul Schatz в 1929 году. Это выпуклая оболочка каркаса, сделанного из двух соединённых конгруэнтных окружностей в перпендикулярных плоскостях, так что центр каждой окружности лежит на другой окружности. Расстояние между центрами окружностей равно радиусу окружностей. Одна треть периметра каждого круга лежит внутри выпуклой оболочки, поэтому одна и та же форма может быть также сформирована как выпуклая оболочка двух оставшихся круглых дуг, каждая из которых охватывает угол 4π/3.
Подобная структура, состоящая из двух окружностей, расположенных под углом 90° к друг-другу, приходит в движение при помощи двух сервомашинок, которые перемещают грузы по периметру каждого круга, что изменяет центр тяжести робота и заставляет его катиться вперёд или назад.
Мозг робота — контроллер Arduino Uno, к которому подключены не только сервомашинки, но и инфракрасный датчик движения HC-SR501 (позволяет роботу реагировать на окружающую среду), Bluetooth-модуль HC-05 (через него осуществляется управление роботом через SerialPortPorfile (SPP)) и небольшой динамик (обеспечивает звуковую обратную связь).
Код скетча — 200713_mOLOID.ino
///Libraries #include <SoftwareSerial.h> #include <Servo.h> #include <pitches.h> //// /// Custom Functions //Smooth servo movement void MoveCts(Servo serv, int aim, int delayTime){ int stepSize = 1; //int delayT = 20; int delayT = delayTime; int current = serv.read(); int diff = aim - current; if (diff < 0) diff = -1*diff; int steps = diff/stepSize; if(aim > current){ for(int i = 1; i < steps + 1; i++){ serv.write(current + i * stepSize); delay(delayT); } } else if (aim < current){ for(int i = 1; i < steps + 1; i++){ serv.write(current - i * stepSize); delay(delayT); } } } //Making the OLOID move, i.e. into an mOLOID void Move(bool dir, int velocity, Servo serv1, Servo serv2){ int vel = 0; vel = velocity; if (dir == 0){ MoveCts(serv1,0, vel); delay(vel); MoveCts(serv2,90, vel); MoveCts(serv2,180, vel); delay(vel); MoveCts(serv1,90, vel); MoveCts(serv1,180, vel); delay(vel); MoveCts(serv2,90, vel); MoveCts(serv2,0, vel); delay(vel); MoveCts(serv1,90, vel); delay(vel); } else { MoveCts(serv1,180, vel); delay(vel); MoveCts(serv2,90, vel); MoveCts(serv2,180, vel); delay(vel); MoveCts(serv1,90, vel); MoveCts(serv1,0, vel); delay(vel); MoveCts(serv2,90, vel); MoveCts(serv2,0, vel); delay(vel); MoveCts(serv1,90, vel); delay(vel); } } //// ///Variables #define rxPin 11 ///blue #define txPin 12 ///green #define buzz 7 //buzzer #define sens 13 //sensor bool power = 0; bool dir = 0; int motState = LOW; int sensVal = 0; Servo serv1; Servo serv2; int delayT = 10; SoftwareSerial btSerial(rxPin, txPin); String btData; // Sound Setup int melody1[] = { NOTE_G7, NOTE_G7, NOTE_AS7, NOTE_G7 }; //switch on int melody2[] = { NOTE_AS7, NOTE_AS7, NOTE_G7, NOTE_AS7 }; //sensor triggered movement int melody0[] = { NOTE_AS7, NOTE_AS7, NOTE_G7 }; //switch off int durations1[] = { 4,4,8,8 }; int durations2[] = { 4,4,8,8 }; int durations0[] = { 4,4,4 }; int songLength1 = sizeof(melody1)/sizeof(melody1[0]); int songLength2 = sizeof(melody2)/sizeof(melody2[0]); int songLength0 = sizeof(melody0)/sizeof(melody0[0]); //// ///Setup void setup() { serv1.attach(6); serv2.attach(8); pinMode(buzz, OUTPUT); pinMode(sens, INPUT); btSerial.begin(9600); btSerial.println("bluetooth available"); } //// ///Loop void loop() { if (btSerial.available()) { btData = btSerial.readString(); if(btData == "off") { power = 0; for (int thisNote = 0; thisNote < songLength0; thisNote++){ int duration = 3000/ durations0[thisNote]; tone(buzz, melody0[thisNote], duration); // pause between notes int pause = duration * 0.3; delay(pause); // stop the tone noTone(buzz); } MoveCts(serv1, 90, delayT); MoveCts(serv2, 0, delayT); btSerial.println("Device is off."); //serv1.write(90); //serv2.write(0); } else if (btData == "on") { power = 1; for (int thisNote = 0; thisNote < songLength1; thisNote++){ int duration = 3000/ durations1[thisNote]; tone(buzz, melody1[thisNote], duration); // pause between notes int pause = duration * 0.3; delay(pause); // stop the tone noTone(buzz); } MoveCts(serv1, 90, delayT); MoveCts(serv2, 0, delayT); btSerial.println("Device is on."); //serv1.write(90); //serv2.write(0); } else { int btNumb = btData.toInt(); if (btNumb == 0) btNumb = 10; if (btNumb < 0) { dir = 1; delayT = -btNumb; } else { delayT = btNumb; dir = 0; } //btSerial.println("Input unknown. Only on/off."); } } if (power){ sensVal = digitalRead(sens); if (sensVal == HIGH){ if (motState == LOW){ btSerial.println("Motion detected!"); motState = HIGH; for (int thisNote = 0; thisNote < songLength2; thisNote++){ int duration = 3000/ durations2[thisNote]; tone(buzz, melody2[thisNote], duration); // pause between notes int pause = duration * 0.3; delay(pause); // stop the tone noTone(buzz); } for(int i = 0; i < 3; i++){ Move(dir, delayT, serv1, serv2); } } } else{ MoveCts(serv1, 90, delayT); MoveCts(serv2, 0, delayT); //serv1.write(90); //serv2.write(0); if (motState == HIGH){ btSerial.println("Motion ended!"); motState = LOW; } } } } ////
Ссылки
The Moving OLOID - a Different Pet in Different Times
По теме
Sneaky - интерактивный змееподобный робот
MORPH - робот гуляющий по парку
Робот-червяк на базе Arduino
Halfbug - ползающий робот на Arduino