original in en Katja and Guido Socher
en to ru Ilya Palagin
Катя является немецким редактором LinuxFocus. Она любит Тукса, фильмы и фотографию, а также море. Ее домашнюю страницу можно найти здесь.
Гвидо уже долгое время поклонник Linux, который нравится ему за то, что создан честными и открытыми людьми. Это одна из причин, по которой мы называем эту систему открытой. Вот страница Гвидо: linuxfocus.org/~guido.
Роботы всегда очаровывали нас, так что мы обрадовались, когда нашли книгу c инструментарием для сборки маленького насекомоподобного робота по имени Стикито. Стикито в какой-то степени особенный робот, так как он не имеет мотора, но ходит, потому что к его ногам прикреплен нитинол, так что робот передвигается совершенно бесшумно, как настоящее насекомое. Но когда мы построили Стикито, то заметили, что из-за недостаточно хорошего сцепления с поверхностью двигался он очень-очень медленно. К счастью, книга также включала описания конструкций других киберов, что окончательно вдохновило нас на создание робота, о котором вы можете здесь прочитать.
Для сборки робота мы использовали следующие материалы:
Рис.1: Монтажная плата |
Рис.2: Пассатижи |
Для туловища вам вначале понадобятся три монтажных платы, одна с отверстиями 6х6 и две
с отверсиями 6х7, а также 4см 2мм-ой латунной трубки c 3.7мм струны.
Рис.4: "Хребет" и шина подвода питания
Разрежьте латунную трубку на 8мм, 17.5мм, и 8мм части как показано на рис.4. Вы можете
сделать это, покатав трубку взад и вперед острым кухонным ножом и затем согнув ее. Трубка
сломается в тех местах, где вы сделали бороздки ножом. Важно, чтобы трубка была немного
длиннее, чем плата с 6х6 отверстиями. Отрежьте около 3.7см струны. Длина в результате
должна быть примерно на 3мм больше, чем три части трубки, сложенные вместе. Пропустите
струну сквозь все три трубки.
Средняя трубка должна свободно вращаться, в то время как крайниe нужно припаять к струне.
Рис.5: Припаяйте платы к "хребту"
Итак, средняя трубка припаяна к плате с 6х6 отверстиями. Убедитесь, что она может
вращаться. Две другие трубки припаяны к остальным двум платам.
Теперь возьмите маленькую монтажную плату с 2х7 отверстиями. Ее следует поставить краем на
середину латунной трубки. Проделайте бороздку на монтажной плате с
помощью резака или напильника. Припаяйте маленькую монтажную плату к середине латунной
трубки, как показано на рисунке:
Рис.6: Установка платы 2х7.
Обработайте наждачной бумагой 1мм-ю латунную трубку и отрежьте от нее несколько кусочков
длиной 4мм. Катайте трубку лезвием кухонного ножа и затем ломайте ее. Вам
понадобится 16 зажимов, однако сделайте несколько запасных.
Поскольку мы будем много обжимать, сейчас вам лучше поэкспериментировать
с небольшим кусочком нитинола: вложите конец нитиноловой проволоки в
зажим и сожмите его пассатижами. Эта процедура называется обжим. Позаботьтесь о том,
чтобы купить хорошие пассатижи, так как необходимо очень большое усилие для сжатия трубки.
Вы можете также пропустить нитинол через тонкую наждачную бумагу для лучшего
электрического контакта.
А сейчас мы займемся нитиноловой проволокой, которая необходима для
перемещения ног вверх и вниз.
Рис. 7: "Мост"
Натяните проволоку так, как если бы вы хотели построить мост. Начните с одной
стороны, где пропустите нитинол сквозь последнее свободное отверстие cлева.
Завяжите узел на проволоке (для уверенности, что соединение надежное) и наденьте на нее зажим
(приготовленный заранее 4мм-й отрезок трубки), после чего обожмите его. Пропустите проволоку
через второе отверстие сверху и затем через последнее свободное отверстие слева.
С нижней стороны завяжите узел и обожмите его. Нитиноловая проволока должна быть натянута,
но не слишком сильно. Если вы слегка коснетесь ее, она должна провинуть на 2-4мм.
Если проволока недостаточно натянута, или натянута слишком сильно, робот не будет двигаться
как надо. Припаяйте зажимы к плате.
Сделайте то же самое на второй стороне
Перед тем, как продолжить, испытайте, как все это работает. Возьмите миниатюрную
батарейку на 1.5В и подсоедините ее к нитиноловой проволоке. Когда проволока
сократиться, средняя часть тела робота должна повернуться на 10-20 градусов. Будьте
осторожны, не держите батарейку подсоединенной дольше 1 секунды. Вы повредите проволоку,
если перегреете ее.
Рис.8: Как согнуть проволоку
Откусите от струны три отрезка длиной 10см, они будут использоваться в качестве ног.
Согните каждую на расстоянии 1.5см от обоих концов. Припаяйте струны к трем частям робота.
Они должны быть параллельны друг другу.
Рис. 9, 10: Как укрепить ноги на роботе
Теперь вы должны прикрепить нитиноловую проволоку, играющую роль привода, ко всем
шести ногам.
Рис. 11: Установка приводов
Пропустите нитиноловую проволоку сверху сквозь зажим и сквозь отверстие
на монтажной плате. Расстояние до струны - 3 отверстия. Обожмите ее как
следует (см. рис. ниже).
Затем тяните зажим по струне, пока не достигнете коленного изгиба.
Вставьте нитинол в зажим и плотно обожмите его. Теперь самое трудное. Удерживая
робота с помощью небольших тисков, обмотайте его ноги клейкой лентой или
дополнительным медным проводом. Музыкальная струна создает противодействие
нитинолу, который должен вплотную прилегать к ней. Струну следует вытянуть
через отверстие в 1-й монтажной плате в направлении нитинола, после чего зажим
должен быть припаян к ноге.
Рис. 12: Нитинол и струна на одном уровне
Убедитесь, что нитинол и струна находятся на одном и том же уровне.
При сокращении нитинола ноги должны двигаться назад, а не перемещаться вверх и вниз.
Сделайте то же самое с остальными пятью ногами.
Ноги и струна с латунными трубками посередине робота выполняют функции шины
подвода питания, поэтому между ними должен быть электрический контакт. Однако
средняя часть туловища должна вращаться, вследствие чего у нее отсутствует надежное
соединение. Мы исправим положение, взяв 3см 0.1мм-го провода в лаковой изоляции и
намотав его на неиспользованную латунную трубку, чтобы получилась небольшая спираль.
Выньте трубку и припаяйте спираль к середине внутренней пары ног и внешней паре ног.
Свитый в виде спирали провод обеспечивает максимальную гибкость.
Когда робот будет готов, припаяйте 0.5м (или длиннее, если хотите) отрезки 0.1мм провода к зажимам на плате и припаяйте сами зажимы к монтажной плате. Нам понадобится 9 проводов, 6 для ног, 2 для поднятия пар ног вверх и вниз и 1 для шины питания. Вы можете припаять другие концы проводов к небольшому коннектору, который затем вы будете включать в соответствующее гнездо в блоке управления.
Наше насекомое создано для трехногой ходьбы. Это означает, что пока три ноги
(две на левой и одна на правой стороне) находятся на земле, другие три приподняты.
Когда робот идет, ноги на земле двигаются в одном направлении, в то время как
приподнятые - в обратном.
Рис. 13: Способ хотьбы
Блок управления позволяет использовать ваш PC для контроля над
приводами робота, включается он в параллельный порт.
Когда мы разрабатывали нашу компьютерную программу, то первым делом проверяли ее
на светодиодах и включали провода управления в гнезда лишь после того, как
светодиоды показывали правильную походку, что говорило о корректной работе программы.
Робот весьма прожорлив. Вам нужно пропускать ток 200-250мА через нитиноловую
"мускулатуру", чтобы заставить ее сокращаться. Сопротивление 3см нитиноловой проволоки
на ноге около 7 Ом. Всегда запускайте программу перед подачей питания на
блок управления, потому что в этом случае значение управляющего сигнала на
контактах будет "Выкл", что позволит избежать повреждения нитинола. Поскольку BIOS
компьютера устанавливает случайные
значения на контактах параллельного порта, некоторые
из них могут получить состояние "Вкл", вследствие чего ток через проволоку будет протекать
гораздо дольше одной секунды и повредит ее. Время охлаждения нитинола должно
равняться 1.5 времени нагрева.
Электросхема:
Рис. 14: Электросхема
Как вы видите на схеме выше, мы используем стабилизированный блок питания.
Это нужно для обеспечения хорошего стабильного питания и для защиты
параллельного порта. В качестве внешнего источника вы можете подсоединить
любой блок питания с постоянным током и напряжением на выходе 6В и 24В.
Микросхема 7805 является
стандартным регулятором напряжения. Единственная вещь, на которую вам следует
обратить внимание, это расположение двух конденсаторов (470мкФ и 0.1мкФ).
Установите их как можно ближе к регулятору напряжения 7805, потому что он
может начать раскачиваться и выйдет из строя.
Устройство управления должно быть собрано восемь раз. По разу для каждой ноги
и два раза для перемещения пар ног вверх и вниз. Мы используем маленький n-p-n
Дарлингтон-транзистор, потому что нашему роботу нужен сильный ток.
BC875 или BC618 могут коммутировать около 500мА. Резистор 47кОм на входе
нужен для обеспечения состояния "Выкл" открытой цепи (например, когда
компьютер не подключен). Напряжение на параллельном порту около 4В для состояния
"Вкл" и ниже 1В для "Выкл". Транзистор работает только как коммутатор.
Резисторы 15 Ом ограничивают ток и защищают ноги робота и транзистор.
Светодиоды показывают состояние ("Вкл" или "Выкл").
Ниже вы видите снимки монтажа. Красные светодиоды (включенные параллельно приводам робота)
трудно различить, поскольку мы использовали прозрачные красные светодиоды.
Мы сделали резисторы на 15 Ом из константановой проволоки, свитой в спираль, но
лишь потому, что у нас было ее много. Дешевле купить два резистора
мощностью 2Вт.
Параллельный порт был разработан в качестве выходного порта с персонального компьютера
на принтер. Некоторые параллельные порты позволяют работу на вход и выход.
Здесь мы используем порт только как выход. В одной из следующих статей мы подключим
к роботу датчики и будем использовать входные линии. Хотя параллельный порт имеет
25 линий, мы используем лишь 9. Восемь линий использованы как выходные линии и одна
для подключения электрической земли.
Цоколевка параллельного порта:
25-контактный D-SUB "мама" для PC. Контакт Обозначение Направление Описание 1 STROBE [-->] Строб (готовность данных) 2 D0 [-->] 0 бит данных 3 D1 [-->] 1 бит данных 4 D2 [-->] 2 бит данных 5 D3 [-->] 3 бит данных 6 D4 [-->] 4 бит данных 7 D5 [-->] 5 бит данных 8 D6 [-->] 6 бит данных 9 D7 [-->] 7 бит данных 10 ACK [<--] Контроль приема данных 11 BUSY [<--] Принтер не готов к приему (занят) 12 PE [<--] Кончилась бумага 13 SEL [<--] Контроль состояния принтера 14 AUTOFD [-->] Автоматический перевод строки после перевода каретки 15 ERROR [<--] Ошибка 16 INIT [-->] Инициализация принтера 17 SELIN [-->] Принтер готов работе 18 GND [---] Корпус 19 GND [---] Корпус 20 GND [---] Корпус 21 GND [---] Корпус 22 GND [---] Корпус 23 GND [---] Корпус 24 GND [---] Корпус 25 GND [---] КорпусВы подсоедините блок управления к 18-му контакту (Корпус) и к контактам вывода данных 2-9
==== pprobi.c ===== /* vim: set sw=8 ts=8 si : */ /* * Эта программа является свободным программным обеспечением. * Вы можете распространять * или изменять ее в соответствии с Общедоступной лицензией GNU. * Подробности на http://www.gnu.org/copyleft/. * * Авторы Katja Socher <[email protected]> * и Guido Socher <[email protected]> * */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <math.h> #include <signal.h> #include "robi.h" /* ----------- */ static int opt_r=0; static int fd=0; /* ----------- */ /* ----------- */ void help() { printf("pprobi -- control software for a walking robot\n\ USAGE: pprobi [-h] [parport-device]\n\ \n\ OPTIONS:\n\ -h this help\n\ -r reset the parallel port data pins (all zero) and exit\n\ \n\ The default device is /dev/parport0 \n\ "); #ifdef VERINFO puts(VERINFO); #endif exit(0); } /* Signal handler: all off then exit */ void offandexit(int code) { robi_setdata(fd,0); set_terminal(0); exit(0); } /* ----------- */ int main(int argc, char **argv) { int state,bpat,alternate; char *dev; /* The following things are used for getopt: */ int ch; extern char *optarg; extern int optind; extern int opterr; opterr = 0; while ((ch = (char)getopt(argc, argv, "hr")) != -1) { switch (ch) { case 'h': help(); /*no break, help does not return */ case 'r': opt_r=1; break; case '?': fprintf(stderr, "serialtemp ERROR: No such option. -h for help.\n"); exit(1); /*no default action for case */ } } if (argc-optind < 1){ /* less than one argument */ dev="/dev/parport0"; }else{ /* the user has provided one argument */ dev=argv[optind]; } fd=robi_claim(dev); /* robi_claim has its own error checking */ /* catch signals INT and TERM and switch off all data lines before * terminating */ signal(SIGINT, offandexit); signal(SIGTERM, offandexit); /* initialize parpprt data lines to zero: */ robi_setdata(fd,0); set_terminal(1); /* set_terminal has its own error handling */ state=0; alternate=0; if (opt_r){ offandexit(1); } while(1){ ch=getchoice(); if (ch!=0) state=ch; if (ch == ' '){ printf("Stop\n"); robi_setdata(fd,0); usleep(500*1000); } if (ch == 'q'|| ch == 'x'){ printf("Quit\n"); break; } if (state=='l'){ /*right */ printf("walking right\n"); walkright(fd); } if (state=='h'){ /*left */ printf("walking left\n"); walkleft(fd); } if (state=='j'){ printf("walking back\n"); walkback(fd); } if (state=='k'){ if (alternate){ printf("walking straight on a\n"); walkstraight_a(fd); }else{ printf("walking straight on b\n"); walkstraight_b(fd); } alternate=(alternate +1) %2; } } /* we get here if q was typed */ set_terminal(0); return (0); } ==== robi.c ===== /* vim: set sw=8 ts=8 si : */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License. * See http://www.gnu.org/copyleft/ for details. * * Written by Katja Socher <[email protected]> * and Guido Socher <[email protected]> * */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <sys/types.h> #include <sys/time.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> #include <linux/ppdev.h> #include <sys/ioctl.h> #include <termios.h> #include "robi.h" /* like printf but exit the program */ static int die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); exit(1); } /* get one character from stdin * Returns non zero if char was read otherwise zero * The arrow keys are mapped as follows: * <- = h * -> = l * v = j * ^ = k */ int getchoice() { int c; char s[20]; if (fgets(s,20,stdin)){ c=s[0]; switch (c){ case 0x1b: /* ESC */ if (s[1] == 0x5b){ /* arrow keys are pressed */ switch (s[2]){ case 0x41: /*up arrow*/ c='k'; break; case 0x42: /*down arrow*/ c='j'; break; case 0x44: /*l arrow*/ c='h'; break; case 0x43: /*r arrow*/ c='l'; break; default: c=0; } }else{ c=0; } break; case ' ': case 'h': case 'j': case 'k': case 'l': case 'q': case 'x': break; default: c=0; } return(c); } return(0); } /* Set the Terminal to Non Canonical mode with echo off * or reset the terminal. * USAGE: set_terminal(1) for canonical */ int set_terminal(int canonical) { static struct termios originalsettings; struct termios newsettings; static int origok=0; /* set if originalsettings valid */ if (canonical){ /* save original settings and set canonical mode*/ tcgetattr(fileno(stdin),&originalsettings); newsettings=originalsettings; newsettings.c_lflag &= ~ICANON; newsettings.c_lflag &= ~ECHO; newsettings.c_cc[VMIN]=0; /* do not block */ newsettings.c_cc[VTIME]=1; /* 100 ms */ if (tcsetattr(fileno(stdin),TCSANOW,&newsettings) !=0){ die("ERROR: could not set terminal attributes on stdin\n"); } origok=1; }else{ if (origok){ /* restore settings */ tcsetattr(fileno(stdin),TCSANOW,&originalsettings); } } return(0); } /* open /dev/parportX device and claim it. * USAGE: fd=robi_claim("/dev/parport0"); * The return value is a file descriptor used by other * functions such as robi_setdata */ int robi_claim(char *dev) { int fd,i; fd = open(dev, O_RDWR ); if (fd < 0) { die("ERROR: cannot open device %s\n",dev); } i=0; /* we need exclusive rights as we do not set the control lines*/ /*ioctl(fd, PPEXCL, &i)&& die("ERROR: request for exclusive rights failed\n");*/ ioctl(fd, PPCLAIM, &i)&&die("ERROR: could not claim parport\n"); return(fd); } /* Walk left */ int walkleft(int fd) { /* first B legs to ground */ robi_setdata(fd,LEGBD); usleep(400 *1000); /* all A legs 1 step */ robi_setdata(fd, LEGB1 | LEGB3 ); usleep(1100 *1000); /* first A legs to ground, cool B*/ robi_setdata(fd,LEGAD); usleep(400 *1000); robi_setdata(fd,0); usleep(1000 *1000); return(0); } /* Walk right */ int walkright(int fd) { /* first A legs to ground */ robi_setdata(fd,LEGAD); usleep(500 *1000); robi_setdata(fd, LEGA3 | LEGAD); usleep(300 *1000); /* all A legs 1 step */ robi_setdata(fd, LEGA1 | LEGA3 ); usleep(1100 *1000); /* first B legs to ground, cool A*/ robi_setdata(fd,LEGBD); usleep(400 *1000); robi_setdata(fd,0); usleep(1000 *1000); return(0); } /* Walk with all 3 legs 1 step forward */ int walkstraight_a(int fd) { /* first A legs to ground */ robi_setdata(fd,LEGAD); usleep(800 *1000); /* all A legs 1 step */ robi_setdata(fd, LEGA1 | LEGA2 | LEGA3 ); usleep(1000 *1000); /* first B legs to ground, cool A*/ robi_setdata(fd,LEGBD); usleep(500 *1000); robi_setdata(fd,0); usleep(1200 *1000); return(0); } /* Walk with all 3 legs 1 step forward */ int walkstraight_b(int fd) { /* first B legs to ground */ robi_setdata(fd,LEGBD); usleep(400 *1000); /* all B legs 1 step */ robi_setdata(fd,LEGB1 | LEGB2 | LEGB3); usleep(1000 *1000); /* A down and cool */ robi_setdata(fd,LEGAD); usleep(800 *1000); robi_setdata(fd,0); usleep(1200 *1000); return(0); } /* Walk with all 6 legs 1 step back */ int walkback(int fd) { /* first A legs to ground */ robi_setdata(fd,LEGAD); usleep(800 *1000); /* all B legs 1 step in the air*/ robi_setdata(fd, LEGB1 | LEGB2 | LEGB3 ); usleep(500 *1000); /* first B legs to ground, cool A*/ robi_setdata(fd,LEGBD); usleep(500 *1000); /* all A legs 1 step in the air*/ robi_setdata(fd,LEGA1 | LEGA2 | LEGA3); usleep(500 *1000); /* A down and cool */ robi_setdata(fd,LEGAD); usleep(800 *1000); robi_setdata(fd,0); usleep(1000 *1000); return(0); } /*---------*/ /* Write a bit pattern to the data lines * USAGE: rc=robi_setdata(fd,bitpat); * The return value is 0 on success. */ int robi_setdata(int fd,unsigned char bitpat) { int rc; rc=ioctl(fd, PPWDATA, &bitpat); return(rc); } ==== robi.h ===== /* vim: set sw=8 ts=8 si et: */ #ifndef H_ROBI #define H_ROBI 1 #define VERINFO "version 0.2" /* the first thing you need to do: */ extern int robi_claim(char *dev); /* write a bit pattern to the data lines of the parallel port: */ extern int robi_setdata(int fd,unsigned char bitpat); /* input and terminal functions */ extern int set_terminal(int canonical); extern int getchoice(); extern int walkstraight_a(int fd); extern int walkstraight_b(int fd); extern int walkback(int fd); extern int walkleft(int fd); extern int walkright(int fd); /* data pins to legs: * A1------=------B1 * = * = * B2------=------A2 * = * = * A3------=------B3 * * * Pin to set A-legs to ground= AD * Pin to set B-legs to ground= BD * * parallel port leg name * ------------------------- * data 0 A1 * data 1 A2 * data 2 A3 * data 3 AD * data 4 B1 * data 5 B2 * data 6 B3 * data 7 BD */ #define LEGA1 1 #define LEGA2 2 #define LEGA3 4 #define LEGAD 8 #define LEGB1 16 #define LEGB2 32 #define LEGB3 64 #define LEGBD 128 #endif
Программа использует интерфейс ppdev ядра версии 2.4.х (вам нужны ядра версий 2.3.х или 2.4.х, с более старыми она не будет работать). Это простой и удобный интерфейс для написания пользовательских драйверов параллельного порта. При использовании более старых ядер мы были бы должны написать модуль ядра или использовать кривой метод, который требовал бы привилегий root для запуска программы. Интерфейс ppdev использует файл устройства /dev/parport0 и путем установки владельца и прав доступа вы можете контролировать, кому позволено использовать этот интерфейс.
Для компиляции ppdev как модуля в ядро вам нужно скомпилировать модуль PARPORT вместе с устройством PPDEV. В файле .config это должно выглядеть следующим образом:
# # Parallel port support # CONFIG_PARPORT=m CONFIG_PARPORT_PC=m CONFIG_PARPORT_PC_FIFO=y # CONFIG_PARPORT_PC_SUPERIO is not set # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set # CONFIG_PARPORT_ATARI is not set # CONFIG_PARPORT_SUNBPP is not set CONFIG_PARPORT_OTHER=y CONFIG_PARPORT_1284=y # # Character devices # CONFIG_PPDEV=m #
В первую очередь программа инициализирует параллельный порт командой ioctl PPCLAIM.
Затем она устанавливает терминал в режим non canonical. Это нужно для
того, чтобы получать ввод напрямую с клавиатуры без необходимости нажимать Enter
после каждого ввода. Потом программа входит в цикл, где вначале проверяет, не было ли
ввода данных пользователем, а затем позволяет роботу двигаться в соответствии с
командой. Если вы не даете команд, программа просто будет продолжать выполнять последнюю
введенную команду (например, двигаться прямо).
Команда ioctl(fd, PPWDATA, &bitpat); используется для наложения
заданной маски на линии данных.
Контакты вашего робота должны быть подсоединены к выходным линиям блока управления следующим образом:
Ноги: A1------=------B1 = = B2------=------A2 = = A3------=------B3 Контакт для подключения A-ног на корпус = AD Контакт для подключения B-ног на корпус = BD Соответствие выходных линий блока управления: data 0 A1 data 1 A2 data 2 A3 data 3 AD data 4 B1 data 5 B2 data 6 B3 data 7 BDЛиния данных "0" является выходом блока управления, который подсоединяется к параллельному порту на 2-й контакт (D0).
Мы надеемся, что вы получите много удовольствия, собирая робота. Сообщите нам о нем, особенно если он имеет другую конструкцию!