Робот-компаньон Аси (Ананси)
Компоненты и расходные материалы
![]() |
| × | 1 | |||
![]() |
| × | 1 | |||
| × | 1 | ||||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Необходимые инструменты и машины
![]() |
| |||
![]() |
|
Об этом проекте
История
Первоначально этот проект должен был быть Xpider от Thingiverse. Затем я говорю «Архимед» Алекса Глоу. Это взорвало мой разум. Я так сильно хотел одну. Итак, я приступил к работе над собственным роботом-компаньоном. Я решил, что я не сова, и хотел, чтобы мой фамильяр был особенным. Затем я вспомнил африканскую историю об Ананси, пауке, обманщике и боге сказок. Я решил спроектировать бота по идее истории, и так родилась Asi (на самом деле это были прототипы Asi_v4, v1-3).
Сборка
Первоначальным дизайном был Xpider, но я поднял его на ступеньку выше, отредактировал много вещей, многие из них выкинули наружу, и, ну, знаете, переделали. Это большинство деталей, которые вам нужно распечатать.

Сборка довольно понятна, но все же вот несколько картинок.


Что касается электроники, вы обычно можете поместить их в верхнюю или нижнюю часть головки (ваше решение), но сервопривод должен быть прикреплен таким образом. Пожалуйста, убедитесь, что на нем есть шестеренка.

Asi управляется двумя микроконтроллерами, Trinket и Arduino Nano. Брелок контролирует движение глаза, благодаря сервоприводу он поворачивается назад и вперед с произвольными интервалами. Arduino Nano управляет глазом. Это также случайно, когда он смотрит вокруг и тому подобное, обычно люди предполагают, что он смотрит на них.



Обратите внимание, у меня они есть на двух небольших макетных платах, которые последовательно соединены с 4 батареями AA. (Вы также можете использовать литий-ионный аккумулятор 3,7 200 мАч. С литий-ионным аккумулятором у меня были случаи, когда по какой-то причине он не работал, поэтому я бы использовал две отдельные литиевые батареи и прикреплял их к одному выключателю. так что все начинается сразу.)
Голова - это просто новогодний шар, который мне достался на праздниках. Я сделал шаг назад и слегка обрызгал его черной краской. Затем возьмите немного горячего клея и приклейте его к шее Аси, и БУМ вот и голова!



Наконец, как я его ношу. Я просто взял арматуру, протянул ее через отверстия в нижней части Asi и намотал на плечевой рюкзак своего рюкзака.

Код
- Аси Ай
- Аси Шея с безделушкой
Asi Eye Arduino
код для Asi eye#include// Мы всегда должны включать библиотеку LedControl # include "LedControl.h" / * Создать объект LetControl, определить контактные соединения. У нас есть 2 MAX72XX для глаз. * / # определить PIN_EYES_DIN 12 # определить PIN_EYES_CS 11 # определить PIN_EYES_CLK 10LedControl lc =LedControl (PIN_EYES_DIN, PIN_EYES_CLK, PIN_EYES_CS, 2); // RotateMatrix0 =false; // повернуть матрицу 0 на 180 градусов rotateMatrix1 =false; // поворот 1 матрицы на 180 градусов // определение глазного яблока без зрачка byte eyeBall [8] ={B00111100, B01111110, B11111111, B11111111, B11111111, B11111111, B01111110, B00111100}; byte eyePupil =B11100111; // сохраняет текущее состояние LEDsbyte eyeCurrent [8]; int currentX; int currentY; int cntLoop =0; int cntEffect =0; // минимальная и максимальная позиции # определить MIN -2 # определить MAX 2 // задержки # определить DELAY_BLINK 40 // выполнить эффект каждые # итераций цикла, 0 для отключения # define EFFECT_ITERATION 4 / * настройка Arduino * / void setup () {// MAX72XX находится в режиме энергосбережения при запуске, мы должны выполнить вызов пробуждения lc.shutdown (0, false); lc.shutdown (1, ложь); // устанавливаем низкую яркость lc.setIntensity (0,1); lc.setIntensity (1,1); // очищаем оба модуля lc.clearDisplay (0); lc.clearDisplay (1); // проверка светодиода // байт вертикальной линии b =B10000000; для (int c =0; c <=7; c ++) {для (int r =0; r <=7; r ++) {setRow (0, r, b); setRow (1, r, b); } b =b>> 1; задержка (50); } // полный модуль b =B11111111; для (int r =0; r <=7; r ++) {setRow (0, r, b); setRow (1, r, b); } задержка (500); // очищаем оба модуля lc.clearDisplay (0); lc.clearDisplay (1); задержка (500); // случайное начальное число randomSeed (analogRead (0)); // глаза по центру, сумасшедшее мигание displayEyes (0, 0); задержка (2000); blinkEyes (истина, ложь); blinkEyes (ложь, правда); delay (1000);} / * цикл Arduino * / void loop () {// перемещаемся в случайное положение, ждем случайное время moveEyes (random (MIN, MAX + 1), random (MIN, MAX + 1), 50); задержка (случайная (5, 7) * 500); // время моргания? если (случайный (0, 5) ==0) {задержка (500); blinkEyes (); задержка (500); } // время воздействия? если (EFFECT_ITERATION> 0) {cntLoop ++; если (cntLoop ==EFFECT_ITERATION) {cntLoop =0; если (cntEffect> 6) cntEffect =0; switch (cntEffect) {case 0:// перекрестие crossEyes (); задержка (1000); ломать; case 1:// круговое вращение roundSpin (2); задержка (1000); ломать; case 2:// сумасшедший спин crazySpin (2); задержка (1000); ломать; case 3:// мета глаза methEyes (); задержка (1000); ломать; case 4:// ленивый глаз lazyEye (); задержка (1000); ломать; case 5:// сумасшедшее мигание blinkEyes (true, false); blinkEyes (ложь, правда); задержка (1000); ломать; case 6:// свечение glowEyes (3); задержка (1000); ломать; по умолчанию:перерыв; } cntEffect ++; }}} / * Этот метод мигает обоими глазами * / void blinkEyes () {blinkEyes (true, true);} / * Этот метод мигает глазами в соответствии с предоставленными параметрами * / void blinkEyes (boolean blinkLeft, boolean blinkRight) {// мигает ? если (! blinkLeft &&! blinkRight) return; // закрываем веки for (int i =0; i <=3; i ++) {if (blinkLeft) {setRow (0, i, 0); setRow (0, 7-я, 0); } если (blinkRight) {setRow (1, i, 0); setRow (1, 7-я, 0); } задержка (DELAY_BLINK); } // открываем веки для (int i =3; i> =0; i--) {if (blinkLeft) {setRow (0, i, eyeCurrent [i]); setRow (0, 7-я, eyeCurrent [7-я]); } если (blinkRight) {setRow (1, i, eyeCurrent [i]); setRow (1, 7-i, eyeCurrent [7-i]); } задержка (DELAY_BLINK); }} / * Этот метод перемещает глаза в центральное положение, затем перемещается по горизонтали с обтеканием краев. * / Void crazySpin (int times) {if (times ==0) return; moveEyes (0, 0, 50); задержка (500); байтовая строка =eyePupil; for (int t =0; t > 1; row =row | B10000000; setRow (0, 3, строка); setRow (1, 3, строка); setRow (0, 4, строка); setRow (1, 4, строка); задержка (50); если (t ==0) задержка ((5-i) * 10); // увеличиваем задержку при первой прокрутке (эффект ускорения)} // вращаемся от R к центру for (int i =0; i <5; i ++) {row =row>> 1; если (i> =2) row =row | B10000000; setRow (0, 3, строка); setRow (1, 3, строка); setRow (0, 4, строка); setRow (1, 4, строка); задержка (50); если (t ==(раз-1)) задержка ((я + 1) * 10); // увеличиваем задержку при последней прокрутке (эффект замедления)}}} / * Этот метод пересекает глаза * / void crossEyes () {moveEyes (0, 0, 50); задержка (500); байтовый зрачокR =eyePupil; байтовый зрачокL =eyePupil; // перемещаем учеников вместе for (int i =0; i <2; i ++) {pupilR =pupilR>> 1; ученикR =ученикR | B10000000; ученикL =ученикL <<1; ученикL =ученикL | B1; setRow (0, 3, pupilR); setRow (1, 3, ученикL); setRow (0, 4, pupilR); setRow (1, 4, ученикL); задержка (100); } задержка (2000); // перемещаем зрачки обратно в центр for (int i =0; i <2; i ++) {pupilR =pupilR <<1; ученикR =ученикR | B1; ученикL =ученикL>> 1; ученикL =ученикL | B10000000; setRow (0, 3, pupilR); setRow (1, 3, ученикL); setRow (0, 4, pupilR); setRow (1, 4, ученикL); задержка (100); }} / * Этот метод отображает глазное яблоко со смещением зрачка на значения X, Y от центрального положения. Допустимый диапазон X и Y:[MIN, MAX] Оба светодиодных модуля будут отображать одинаковые глаза * / void displayEyes (int offsetX, int offsetY) {// убедитесь, что смещения находятся в допустимых диапазонах offsetX =getValidValue (offsetX); offsetY =getValidValue (offsetY); // вычисляем индексы для строк учеников (выполняем смещение Y) int row1 =3 - offsetY; int row2 =4 - смещениеY; // определяем байт строки зрачка pupilRow =eyePupil; // выполнить смещение X // битовый сдвиг и заполнить новый бит 1 if (offsetX> 0) {for (int i =1; i <=offsetX; i ++) {pupilRow =pupilRow>> 1; pupilRow =pupilRow | B10000000; }} else if (offsetX <0) {for (int i =-1; i> =offsetX; i--) {pupilRow =pupilRow <<1; pupilRow =pupilRow | B1; }} // строка зрачка не может иметь единиц, в то время как eyeBall имеет байты нулей pupilRow1 =pupilRow &eyeBall [row1]; byte pupilRow2 =pupilRow &eyeBall [строка2]; // отображение на ЖК-матрице, обновление до eyeCurrent for (int r =0; r <8; r ++) {if (r ==row1) {setRow (0, r, pupilRow1); setRow (1, r, pupilRow1); eyeCurrent [r] =pupilRow1; } иначе, если (r ==row2) {setRow (0, r, pupilRow2); setRow (1, r, pupilRow2); eyeCurrent [r] =pupilRow2; } else {setRow (0, r, eyeBall [r]); setRow (1, r, eyeBall [r]); eyeCurrent [r] =eyeBall [r]; }} // обновляем текущие X и Y currentX =offsetX; currentY =offsetY;} / * Этот метод исправляет предоставленное значение координаты * / int getValidValue (int value) {if (value> MAX) return MAX; иначе, если (значение =1; i--) {lc.setIntensity (0, i); lc.setIntensity (1, i); задержка (25); } задержка (150); }} / * Этот метод перемещает глаза в центр, наружу и затем обратно в центр * / void methEyes () {moveEyes (0, 0, 50); задержка (500); байтовый зрачокR =eyePupil; байтовый зрачокL =eyePupil; // вывести учеников на (int i =0; i <2; i ++) {pupilR =pupilR <<1; ученикR =ученикR | B1; ученикL =ученикL>> 1; ученикL =ученикL | B10000000; setRow (0, 3, pupilR); setRow (1, 3, ученикL); setRow (0, 4, pupilR); setRow (1, 4, ученикL); задержка (100); } задержка (2000); // перемещаем зрачки обратно в центр for (int i =0; i <2; i ++) {pupilR =pupilR>> 1; ученикR =ученикR | B10000000; ученикL =ученикL <<1; ученикL =ученикL | B1; setRow (0, 3, pupilR); setRow (1, 3, ученикL); setRow (0, 4, pupilR); setRow (1, 4, ученикL); задержка (100); }} / * Этот метод перемещает оба глаза из текущей позиции в новую * / void moveEyes (int newX, int newY, int stepDelay) {// устанавливает текущую позицию как начальную позицию int startX =currentX; int startY =currentY; // исправляем недопустимые новые значения X Y newX =getValidValue (newX); newY =getValidValue (newY); // вычислить шаги int stepsX =abs (currentX - newX); int stepsY =abs (currentY - новыйY); // необходимо изменить хотя бы одну позицию if ((stepsX ==0) &&(stepsY ==0)) return; // вычислить направление движения, количество шагов, изменение на шаг X Y, выполнить перемещение int dirX =(newX> =currentX)? 1:-1; int dirY =(newY> =currentY)? 1:-1; int steps =(stepsX> stepsY)? stepsX:stepsY; int intX, intY; float changeX =(float) stepsX / (float) steps; float changeY =(float) stepsY / (float) steps; для (int i =1; i <=шаги; i ++) {intX =startX + round (changeX * i * dirX); intY =startY + round (changeY * i * dirY); displayEyes (intX, intY); задержка (stepDelay); }} / * Этот метод опускает и поднимает только правый зрачок * / void lazyEye () {moveEyes (0, 1, 50); задержка (500); // медленно опускаем левый зрачок for (int i =0; i <3; i ++) {setRow (1, i + 2, eyeBall [i + 2]); setRow (1, i + 3, eyeBall [i + 3] и eyePupil); setRow (1, я + 4, eyeBall [я + 4] и eyePupil); задержка (150); } задержка (1000); // быстро поднимаем левый зрачок for (int i =0; i <3; i ++) {setRow (1, 4-i, eyeBall [4-i] &eyePupil); setRow (1, 5-я, eyeBall [5-я] и eyePupil); setRow (1, 6-i, eyeBall [6-i]); задержка (25); }} / * Этот метод вращает зрачки по часовой стрелке * / void roundSpin (int times) {if (times ==0) return; moveEyes (2, 0, 50); задержка (500); для (int я =0; я <раз; я ++) {displayEyes (2, -1); задержка (40); если (i ==0) задержка (40); displayEyes (1, -2); задержка (40); если (i ==0) задержка (30); displayEyes (0, -2); задержка (40); если (i ==0) задержка (20); displayEyes (-1, -2); задержка (40); если (я ==0) задержка (10); displayEyes (-2, -1); задержка (40); displayEyes (-2, 0); задержка (40); displayEyes (-2, 1); задержка (40); если (я ==(раз-1)) задержка (10); displayEyes (-1, 2); задержка (40); если (я ==(раз-1)) задержка (20); displayEyes (0, 2); задержка (40); если (я ==(раз-1)) задержка (30); displayEyes (1, 2); задержка (40); если (я ==(раз-1)) задержка (40); displayEyes (2, 1); задержка (40); если (я ==(раз-1)) задержка (50); displayEyes (2, 0); задержка (40); }} / * Этот метод устанавливает значения в матрицу row. При необходимости выполняется поворот на 180 * / void setRow (int addr, int row, byte rowValue) {if (((addr ==0) &&(rotateMatrix0)) || (addr ==1 &&rotateMatrix1)) {строка =абс (строка - 7); rowValue =перестановка бит (rowValue); } lc.setRow (addr, row, rowValue);} / * Обратные биты в байтах http://www.nrtm.org/index.php/2013/07/25/reverse-bits-in-a-byte/* / byte bitwap (byte x) {байт результат; asm ("mov __tmp_reg__,% [in] \ n \ t" "lsl __tmp_reg__ \ n \ t" / * сдвинуть старший бит для переноса * / "ror% [out] \ n \ t" / * повернуть перенос __tmp_reg__to low бит (в конце концов) * / "lsl __tmp_reg__ \ n \ t" / * 2 * / "ror% [out] \ n \ t" "lsl __tmp_reg__ \ n \ t" / * 3 * / "ror% [out] \ n \ t "" lsl __tmp_reg__ \ n \ t "/ * 4 * /" ror% [out] \ n \ t "" lsl __tmp_reg__ \ n \ t "/ * 5 * /" ror% [out] \ n \ t "" lsl __tmp_reg__ \ n \ t "/ * 6 * /" ror% [out] \ n \ t "" lsl __tmp_reg__ \ n \ t "/ * 7 * /" ror% [out] \ n \ t " "lsl __tmp_reg__ \ n \ t" / * 8 * / "ror% [out] \ n \ t":[out] "=r" (результат):[in] "r" (x)); return (результат);}
Asi Neck с безделушкой Arduino
это то, что я использую, чтобы убедиться, что шея Аси движется вперед и назад// Параметры сервопривода. Значок на брелке ДОЛЖЕН быть 1 или 4. Положение сервопривода // указывается в необработанных тиках таймера / счетчика (1 тик =0,128 миллисекунды). // Время импульса сервопривода обычно составляет 1-2 мс, но может незначительно отличаться для // сервоприводов, поэтому вам может потребоваться настроить эти пределы до соответствовать вашей реальности. # define SERVO_PIN 4 // Контакты 1 или 4 поддерживаются на Trinket # define SERVO_MIN 4 // ~ 1 мс импульс # define SERVO_MAX 26 // ~ 2 мс импульс Adafruit_TiCoServo servo; void setup (void) {#if (F_CPU ==16000000L) // Брелок на 16 МГц требует настройки предварительного масштабирования для правильной синхронизации. // Это ДОЛЖНО быть сделано ДО servo.attach ()! clock_prescale_set (clock_div_1); # endif servo.attach (SERVO_PIN); pinMode (LED_PIN, ВЫХОД); digitalWrite (LED_PIN, HIGH);} uint32_t lastLookTime =0; // Время последнего поворота головы void loop (void) {unsigned long t =millis (); // Текущее время // Если с момента последнего поворота головы прошло более 1/2 секунды ... if ((t - lastLookTime)> 500) {if (random (10) ==0) {// Имеется 1- in-10 шанс ... // ... случайного перемещения головы в новом направлении:servo.write (random (SERVO_MIN, SERVO_MAX)); lastLookTime =t; // Сохраняем время поворота головой для использования в будущем}} // Не связано с проверкой поворота головы, if (random (10) ==0) {// есть шанс 1 из 10 ... // .. "моргания глазом":digitalWrite (LED_PIN, LOW); // Светодиод гаснет delay (random (50, 250)); // на короткий случайный момент digitalWrite (LED_PIN, HIGH); // затем снова ВКЛ} delay (100); // Повторяем loop () примерно 10 раз в секунду}
Изготовленные на заказ детали и корпуса
Фактический конец ножки забыли добавить поворотный механизм для сервопривода, я обычно распечатывал и вставлял сервопривод в середину, затем прикручивал его к корпусу сервопривода Asithe, нижняя часть бедра Asithe к суставу Asileg, винт, который я использую, чтобы соединить ножки Asi с гайкой который идет с винтом, сервопривод шестерни, используемый для поворота головы Asi, рекомендовал бы использовать деталь сервопривода и положить ее посередине. шеяСхема
схема, которую я использовал для Asi Neck

Производственный процесс
- Как создать платформу для роботов Arduino + Raspberry Pi
- Робот-бокс для компакт-дисков Raspberry Pi
- PiCy - крошечный робот на базе Raspberry Pi!
- Робот с подвижной сигнализацией
- Создайте робота Minecraft Creeper
- Архимед:ИИ-робот-сова
- Робот для открытия резюме
- Робот ROS
- Простой робот Pi
- Что такое робот для напитков?