Форум о журнальных коллекциях Деагостини, Ашет, Eaglemoss, Modimio
http://nacekomie.ru/forum/

Вариант программируемого робота на робото-шасси "Робот-шпион"
http://nacekomie.ru/forum/viewtopic.php?f=64&t=4608
Страница 1 из 1

Автор:  YrOM1k [ 20 апр 2012, 20:50 ]
Заголовок сообщения:  Вариант программируемого робота на робото-шасси "Робот-шпион"

День добрый!
Как и обещал выкладываю свою версию программируемого робота.
Что нам понадобиться –
  1. Робото-шасси(№1 по 9)
    Фото:
    Комментарий к файлу: Собранное шасси "Робота-шпиона" выпуски журнала с 1-го по 9-ый
    Вариант программируемого робота на робото-шасси "Робот-шпион"
    Вариант программируемого робота на робото-шасси "Робот-шпион" robot-shassi.jpg [ 25.06 Кб | Просмотров: 12035 ]
  2. Arduino-совместимый клон.
    Фото:
    Комментарий к файлу: Ардуина и моторшилд
    Вариант программируемого робота на робото-шасси "Робот-шпион"
    Вариант программируемого робота на робото-шасси "Робот-шпион" arduino and motorshild.jpg [ 27.7 Кб | Просмотров: 12035 ]
  3. Мотор-шилд(плата управления моторами)
  4. Беспаечная макетная плата. Ну, очень удобная ;)
  5. 7-ь тактовых кнопок
  6. переключатель
  7. 1 двухцветный светодиод(красный-зелёный), я брал 10мА/2.5V.
  8. 10 резисторов 200 Ом 0.125Вт
  9. Набор проводов

По схеме
Фото:
Комментарий к файлу: Схема программируемого робота
Вариант программируемого робота на робото-шасси "Робот-шпион"
Вариант программируемого робота на робото-шасси "Робот-шпион" robot._chema.GIF [ 17.88 Кб | Просмотров: 8865 ]

Собираем на мекетной плате, должно получиться типа так:
Фото:
Комментарий к файлу: Как это выглядит на макетке
Вариант программируемого робота на робото-шасси "Робот-шпион"
Вариант программируемого робота на робото-шасси "Робот-шпион" plata.jpg [ 39.12 Кб | Просмотров: 12035 ]


Скришот с терминала.
Фото:
Комментарий к файлу: В терминале видно прохождение комманд
Вариант программируемого робота на робото-шасси "Робот-шпион"
Вариант программируемого робота на робото-шасси "Робот-шпион" screen.jpg [ 21.4 Кб | Просмотров: 12035 ]

Извиняюсь за качество фоток, по другому не имею возможности.

Скетч(программа для ардуины) -
Код:
/*                                                                                    */
/*                           (с) YrOM1k    ver. 0.5  29.03.2012                       */
/*                                              0.6  15.04.2012                       */

// подключаем нужные библиотеки
#include <Servo.h>         // управление серво-приводами, так-же нужна и для моторов. От неё зависит <LMotorShield.h>
#include <LMotorShield.h>  // управление моторами

/* используемые порты ->
        DIGIT_PORT_0    //  Rx
        DIGIT_PORT_1    //  Tx
        DIGIT_PORT_2    //  Brk2 антивыбег мотора 2
        DIGIT_PORT_3    //  PWM2 скорость мотора  2
        DIGIT_PORT_4    //  Brk1 антивыбег мотора 1
        DIGIT_PORT_5    //  Sig4 servo signal
        DIGIT_PORT_6    //  Sig3 servo signal
        DIGIT_PORT_7    //  Dir2 направление движения
        DIGIT_PORT_8    //  Dir1 направление движения
        DIGIT_PORT_9    //  Sig2 servo signal
        DIGIT_PORT_10   //  Sig1 servo signal
        DIGIT_PORT_11   //  PWM1 скорость мотора 1
        DIGIT_PORT_12   //  Led red
        DIGIT_PORT_13   //  Led green
        ANALOG_PORT_0   //  DIGIT_PORT_14 - ввод с клавиатуры
        ANALOG_PORT_1   //  none -
        ANALOG_PORT_2   //  none  | единственно, что осталось свободно,
        ANALOG_PORT_3   //  none  | если нужно подключить LCD-индикатор
        ANALOG_PORT_4   //  none -
        ANALOG_PORT_5   //  DIGIT_PORT_19 - переключатель режимов "RUN_MODE/PROGRAMM_MODE"
*/

// определяем значения
#define DIGIT_PORT_A         13  // светодиод-индикатор "RUN MODE" - "РЕЖИМ ИСПОЛНЕНИЯ"
#define DIGIT_PORT_B         12  // светодиод-индикатор "PROGRAMM MODE" - "РЕЖИМ ПРОГРАММИРОВАНИЯ"
#define PWM_1                11  // скорость первого ЭД
#define DIR_1                8   // напракление вращения ЭД №1
#define DIR_2                7   // напракление вращения ЭД №2
#define BRK_1                4   // антивыбег первого ЭД
#define PWM_2                3   // скорость второго ЭД
#define BRK_2                2   // антивыбег первого ЭД
#define ANALOG_PORT          0   // Аналоговый порт 0 - используем для клавиатуры
#define RUN_MODE             19  // используем как цифровой вход, для переключателя "RUN MODE-PROGRAMM MODE"
#define MAX_STEP_PROGRAMM    64  // Максимальое кол-во шагов в программе
#define COMMAND_MOVE_FORWARD 1   // Задаём команду "ДВИЖЕНИЕ ВПЕРЁД"
#define COMMAND_MOVE_BACK    2   // Задаём команду "ДВИЖЕНИЕ НАЗАД"
#define COMMAND_TURN_RIGHT   3   // Задаём команду "ПОВОРОТ ВПРАВО"
#define COMMAND_TURN_LEFT    4   // Задаём команду "ПОВОРОТ ВЛЕВО"
#define COMMAND_PAUSE_05S    5   // Задаём команду "ПАУЗА 0.5 сек"
#define COMMAND_PAUSE_10S    6   // Задаём команду "ПАУЗА 1.0 сек"
#define COMMAND_STOP         7   // Задаём команду "СТОП"
#define COMMAND_NONE         0   // нет команды
#define MOTOR_SPEED          254 // скорость моторов
//#define SIG_1                10 // сервопривод №1 - на будущее
//#define SIG_2                9  // сервопривод №2 - на будущее
//#define SIG_3                6  // сервопривод №3 - на будущее
//#define SIG_4                5  // сервопривод №4 - на будущее

// определяем глобальные переменные
int stick, last_stick; // переключатель RUN_MODE/PROGRAMM_MODE
int step_programm;// текущий шаг программы
int matrix_programm[MAX_STEP_PROGRAMM];// массив в котором будем храниться наша программа
char* text_RM = " -- RUN MODE --";
char* text_PM= " -- PROGRAMM MODE --";
char* text_S = " !!!    STOP    !!!";
char* text_P10 = " PAUSED 1.0 sec ";
char* text_P05 = " PAUSED 0.5 sec ";
char* text_L = " TURN LEFT ";
char* text_R = " TURN RIGHT ";
char* text_B = " MOVE BACK ";
char* text_F = " MOVE FORWARD ";
char* text_Y = " I like to move, move it.  --- (c)YrOM1k --- ";
LMotorShield lms; // определяем переменную, которой будем управлять мотороми м сервами через конструктор

// Предоопределяем используемые функции
void Turn_off_led();
void Blink_led(int);
int  Read_key();
int  Run_mode();
int  Programm_mode();
void Clear_matrix();

// Первичная инициализация программируемого робота
void setup(){
  pinMode( RUN_MODE,     INPUT);  // аналоговый порт-5 определяем как цифровой порт-19, на вход
  pinMode( DIGIT_PORT_A, OUTPUT); // порт к которому бодключен зелёный светодиод
  pinMode( DIGIT_PORT_B, OUTPUT); // порт к которому подключен красный светодиод
  Turn_off_led();                 
  Clear_matrix();
  step_programm = 0;
  last_stick = LOW;
  Serial.begin(9600);
  lms.begin(LMS_MOTORS | LMS_SERVOS);
  Serial.println();
  Serial.print(text_Y);   // говорим хеллоу
  Serial.println();
}

// Основная программаы
void loop(){
 
  stick = digitalRead(RUN_MODE);// считываем показание переключателя
  if (last_stick != stick ){    // определяем было-ли перключение режима
    last_stick = stick;
    step_programm = 0;
  }
  if ( stick == HIGH ){
    // если RUN_MODE - лог '1', то включен режим "исполнения"
    if ((step_programm == MAX_STEP_PROGRAMM) || (matrix_programm[0] == COMMAND_NONE)){
      // если кол-во шагов в программе достигло максимума, или после включения робота то ->
      Blink_led(DIGIT_PORT_A);   // если робот
      delay(100);                // выполнил всю
      Turn_off_led();            // программу то
      Blink_led(DIGIT_PORT_B);   // мигаем поочерёдно
      delay(100);                // зелёным а затем
      Turn_off_led();            // красным светодиодом
    }
    else{                        // иначе выполняем введённую программу
      lms.multipleMotorSpeed( LMS_MOTORS, MOTOR_SPEED ); // включаем оба мотора "ПОЛНЫЙ ВПЕРЁД"
      step_programm = Run_mode();
    }
  }
  else{
    // если RUN_MODE - лог '0', то включен режим "программирования"
    if (step_programm == MAX_STEP_PROGRAMM){  // если кол-во шагов в программе при вводе достигло максимума то ->
      Blink_led(DIGIT_PORT_B);                // мигаем красным светодиодом
      Turn_off_led();
      delay(100);
    }
    else{                                     // иначе вводим программу с предварительной очисткой памяти.
      Turn_off_led();
      Clear_matrix();
      step_programm = Programm_mode();
    }
  } 
}

// очистка матрицы, подготовка перед оечередным вводом программы
void Clear_matrix(){
  for (int index = 0; index < MAX_STEP_PROGRAMM; index++){
    matrix_programm[index] = 0;
  } 
}

// принудительно выключить светодиоды
void Turn_off_led(){
  digitalWrite( DIGIT_PORT_A, LOW );
  digitalWrite( DIGIT_PORT_B, LOW );
}

/* функция моргания светодиодом
        |-  DIGIT_PORT_A
        |   
       --- 
       \ / 
       -v-
        |
        |-  DIGIT_PORT_B
       
---------------------------------------
| DIGIT_PORT_A | DIGIT_PORT_B | color |
---------------------------------------
|     HIGH     |    LOW       | green |
---------------------------------------
|     LOW      |    HIGH      |  red  |
---------------------------------------
*/
void Blink_led(int port_AB){
  // включаем светодиод
  digitalWrite(port_AB, HIGH);
  delay(25);
}

// функция считывает с аналогового входа ANALOG_PORT
// значение и определяет какая кнопка была нажата
//
// кнопка 1 - MOVE FORWARD
// кнопка 2 - MOVE BACK
// кнопка 3 - TURN RIGHT
// кнопка 4 - TURN LEFT
// кнопка 5 - PAUSE 0.5 sec
// кнопка 6 - PAUSE 1.0 sec
// кнопка 7 - STOP
//
// ненажата - NONE
int Read_key(){
  int digit;// определяем локальную переменную
  int value = analogRead(ANALOG_PORT);
  digit = COMMAND_NONE; // принудительно устанавливаем "НЕТ КОМАНДЫ"
  if (value > 140 && value < 150 ){
    digit = COMMAND_STOP;
  }
  else{
    if (value > 165 && value < 175 ){
      digit = COMMAND_PAUSE_10S;
    }
    else{
      if (value > 200 && value < 210 ){
        digit = COMMAND_PAUSE_05S;
      }
      else{
        if (value > 250 && value < 260 ){
          digit = COMMAND_TURN_LEFT;
        }
        else{
          if (value > 340 && value < 350 ){
            digit = COMMAND_TURN_RIGHT;
          }
          else{
            if (value > 502 && value < 512 ){
              digit = COMMAND_MOVE_BACK;
            }
            else{
              if (value > 1015 ){
                digit = COMMAND_MOVE_FORWARD;
              }
            }
          }
        }
      }
    }
  }
  delay(250);
  return digit;
}

// останавливаем  ЭД - конец программы
void Stop(){
  Serial.println(text_S);
  lms.multipleMotorStop( LMS_MOTORS );
}
// пауза на одну секунду
void Pause10sec(){
  Serial.println(text_P10);
  lms.multipleMotorStop( LMS_MOTORS );
  delay(1000); // ***
  lms.multipleMotorRun( LMS_MOTORS );
}
// пауза на пол-секунды
void Pause05sec(){
  Serial.println(text_P05);
  lms.multipleMotorStop( LMS_MOTORS );
  delay(500); // ***
  lms.multipleMotorRun( LMS_MOTORS );
}
// поворот в лево
void Left(){
  Serial.println(text_L);
  lms.motorForward( 1 );
  lms.motorBackward( 2 );
  lms.multipleMotorRun( LMS_MOTORS );
  delay(1000); // ***
}
// поворот в право
void Right(){
  Serial.println(text_R);
  lms.motorForward( 2 );
  lms.motorBackward( 1 );
  lms.multipleMotorRun( LMS_MOTORS );
  delay(1000); // ***
}
// движение назад
void Back(){
  Serial.println(text_B);
  lms.multipleMotorBackward( LMS_MOTORS );
  lms.multipleMotorRun( LMS_MOTORS );
  delay(5000); // ***
}
// движение вперёд
void Forward(){
  Serial.println(text_F);
  lms.multipleMotorForward( LMS_MOTORS );
  lms.multipleMotorRun( LMS_MOTORS );
  delay(5000); // ***
}

// функция исполнения введённой программы
// мигаем зелёным светодиодом DIGIT_PORT_A
int Run_mode(){
  int command;
  Serial.println();
  Serial.print(text_RM);
  Serial.println();
  int  index = 0;
  do{
    command = matrix_programm[index];
    Blink_led(DIGIT_PORT_A);              // во время выполнения, каждую команду подтверждаем миганием зелёным светодиодом
    Turn_off_led();
    Serial.print("command --> ");
    if ( command == COMMAND_MOVE_FORWARD ){
      Forward();
    }
    if ( command == COMMAND_MOVE_BACK ){
      Back();
    }
    if ( command == COMMAND_TURN_RIGHT ){
      Right();
    }
    if ( command == COMMAND_TURN_LEFT ){
      Left();
    }
    if ( command == COMMAND_PAUSE_05S ){
      Pause05sec();
    }
    if ( command == COMMAND_PAUSE_10S ){
      Pause10sec();
    }
    if ( command == COMMAND_STOP){
      Stop();
      index = MAX_STEP_PROGRAMM - 1;
    }
    index++;
  }while ( index < MAX_STEP_PROGRAMM );
  return index;
}

// функция программирования робота
// мигаем красным светодиодом DIGIT_PORT_B
int Programm_mode(){
  Serial.println();
  Serial.print(text_PM);
  Serial.println();
  int  button;
  int  index = 0;
  do{            // основной цикл ввода команд
    Turn_off_led();
    do{          // пока не нажата коммандная кнопка
      button = Read_key();
    }while(button == COMMAND_NONE);
    Blink_led(DIGIT_PORT_B);          // после ввода очередной команды мигнём красным светодиодом
    matrix_programm[index] = button;
   
    // ЛОВУШКА !!!
    Serial.print(" matrix_programm[");
    Serial.print(index);
    Serial.print("] = ");
    Serial.println(matrix_programm[index]);
    // ЛОВУШКА !!!
   
    if (button == COMMAND_STOP){   // если введена команда "СТОП"
      index = MAX_STEP_PROGRAMM - 1;
    }
    index++;
  }while( index < MAX_STEP_PROGRAMM );
  return index;
}


Скетч простенький, прокомментирован, но нуждается в доработке -
  • SRAM в которой хранятся переменные очень дефицитный ресурс(2-килобайта ATmega168), а программа хранится в массиве, где элементы int-типа(занимают два байта). Поэтому
    1-е переделать под тип byte
    2-е сами команды занимают полубайт, использую сдвиговые операции можно засунуть в байт две команды.
  • Все второстепенные функции вынести в отдельный файл и вызывать их оттуда. Или оформить как класс.
  • Вместо if-else использовать switch-case.
  • ну ещё, чего по немногу.
  • в скетче команды отмеченные комментариями
    Код:
    // ***
    , нужно подобрать время в миллисекундах в течении которого ЭД будет работать.
Схема пока не использует оптодатчики.

Описание
Робот имеет два режима работы: Режим программирования (Program-Mode) и режим выполнения (Run-Mode).
Умеет выполнять семь комманд -
  1. Верёд
  2. Назад
  3. Поворот вправо
  4. Поворот влево
  5. Пауза на пол-секунды
  6. Пауза на одну секунду
  7. Стоп
Переключателем RunMode-ProgramMode задаём режим работы. Но есть особенность. Если вы во время ввода программы, переведёте робота в режим выполнения, то робот не станет выполнять программу. Каждая введённая программа ДОЛЖНА заканчиваться вводом команды STOP. Переключите тумблер в положение ProgramMode и завершите/введите команду №7 - STOP.
Только после этого робот будет готов выполнять введённую программу.
Светодиодный индикатор показывает 4-ре состояния робота -
  • Во время выполнения команды: одинократное зелёное мигание - означает прохождение/выполнение очередной команды.
  • Во время программирования : одинократное красное мигание - означает подтверждение и сохранение в памяти введённой команды.
  • Во время программирования : постоянное мигание красным - означает, что была введена команда STOP и робот готов выполнять программу, как только вы переключите его в режим RunMode. Типа специально так сделал, что-бы было время поставить робота в нужное место. smile_03
  • Во время выполнения команды: постоянное мигание чередуя красный и зелёный - робот отработал заложенную программу, и ожидает программирования.

Замена и доработка -
  • Двуцветный светодиод можно заменить на два одноцветных(с разным цветом желательно).
    я взял резисторы те, которые были у меня в наличие.
  • На плате свободны четыре аналоговых вывода, их можно использовать для подключения: LCD-индикатора, или двух оптодатчиков(№10 и №11), или аналоговые/цифровые датчики.
  • Ещё есть свободная шина I2C
  • и т.д.
С уважением, smile_16 YrOM1k.

P.S. конструктивная критика и помощь в доработке - приветствуются. smile_20

CatKing'у отпишусь по поводу куда он посчитает нужным переместить тему.

Автор:  greenrat [ 20 апр 2012, 21:16 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

Для начала неплохо)
я бы добавил еще радиоканал для управления, либо ИК
и заменил бы шасси на гусеничные smile_08 но это уже совсем другая история

Автор:  rubra [ 20 апр 2012, 21:47 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

YrOM1k!
Во молодец! Уже кое-что сделал, спасибо за скетч!
Аж завидно! ...Я всё ещё свою ардуину жду, а у меня с начала марта, с огромным трудом добытый МР3-шилд для неё, кваситься(((
Никак не могу приступить....
Хочу сделать звуковое сопровождение событий....

Автор:  Alarus [ 21 апр 2012, 06:09 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

ИХМО Лучше проснифить I2C и подключиться ардуинкой по шине. Думаю количество команд удовлетворит любого пользователя. Надо только помнить что интерфейс 3.3В.

Автор:  YrOM1k [ 21 апр 2012, 15:10 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

greenrat писал(а):
я бы добавил еще радиоканал для управления, либо ИК
закажу для начала блютуз модуль для ардуины, а как приедет попробую.
Скетч-снифером займусь в свободное время.

Автор:  Artem122 [ 20 июн 2012, 12:10 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

А вот с этой ардуино можно что нибудь сделать http://www.parkflyer.ru/35955/product/4 ... fcat=20156 (не реклама) ?

Автор:  TheTERMINATOR [ 20 июн 2012, 12:56 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

Artem122 писал(а):
(не реклама)

А пожохе именно на рекламу.

Чем эта плата отличается от платы автора темы?

Автор:  emax [ 25 июн 2012, 20:10 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

http://habrahabr.ru/post/146489/#habracut

Автор:  Boriss [ 25 июн 2012, 22:55 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

emax писал(а):
http://habrahabr.ru/post/146489/#habracut

Прелесть какая. Да и комментарии не отстают.

Разработчики embedded-систем спорят про ардуину с любителями-хоббистами, не любящими паять всякое.

Это типа как если бы конструкторы Boeing спорили со стендовыми авиамоделистами. Про размер площадки под стенд для испытания реактивных двигателей smile_02

Автор:  Digi [ 07 сен 2012, 17:28 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

Посмотрел, как робот определяет подключеные к нему устройства.
По включению пытается читать данные из какого либо устройства, если приходит 0xff или NACK - значит устройства нет.

Известные устройства
0x40 модуль двигателя
0х40 00 LL RR (LL - мощность и направление левого двигателя, RR правого)
0x50 - RGB контроллер и звук
0x50 00 AB (A,B - биты светодиодов левой и правой стороны)
0x50 01 01 - пищит


Вариант программируемого робота на робото-шасси "Робот-шпион"

Time [s],Event
-0,0000090,Start
0,0000090,Setup read from 0x40. +ACK
0,0001740,Read 0x00 from 0x40. +ACK
0,0003130,Stop
0,0003400,Start
0,0003580,Setup read from 0x50. +ACK
0,0005230,Read 0x00 from 0x50. +ACK
0,0006620,Stop
0,0006890,Start
0,0007070,Setup read from 0x58. +No ACK
0,0008710,Read 0xFF from 0x58. +ACK
0,0010100,Stop
0,0010390,Start
0,0010570,Setup read from 0x60. +No ACK
0,0012220,Read 0xFF from 0x60. +ACK
0,0013600,Stop
0,0013900,Start
0,0014080,Setup read from 0x68. +No ACK
0,0015720,Read 0xFF from 0x68. +ACK
0,0017100,Stop
0,0017400,Start
0,0017580,Setup read from 0x70. +No ACK
0,0019220,Read 0xFF from 0x70. +ACK
0,0020600,Stop
0,0020900,Start
0,0021080,Setup read from 0x78. +No ACK
0,0022710,Read 0xFF from 0x78. +ACK
0,0024100,Stop
0,0024600,Start
0,0024780,Setup read from 0x40. +ACK
0,0026430,Read 0x00 from 0x40. +ACK
0,0027990,Read 0x00 from 0x40. +ACK
0,0029550,Read 0x00 from 0x40. +ACK
0,0031110,Read 0x87 from 0x40. +ACK
0,0032660,Read 0x00 from 0x40. +ACK
0,0034220,Read 0x00 from 0x40. +ACK
0,0035780,Read 0x03 from 0x40. +ACK
0,0037160,Stop

Автор:  Yesterday [ 07 сен 2012, 17:45 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

В свою очередь, когда будет пульт, постараюсь с осциллографа картинок накидать (если будет такая оказия).

Автор:  alexspy2 [ 09 окт 2012, 18:28 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

клевое шасси для любителей собрать робота самому http://www.parkflyer.ru/32825/product/5 ... fcat=56912

Автор:  RUSD [ 12 ноя 2012, 14:07 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

Только там движки много жрут и на коврах туговато поворачивает (у самого такое ползает по дому).

Автор:  AVKrobotics [ 02 фев 2013, 08:55 ]
Заголовок сообщения:  Re: Вариант программируемого робота на робото-шасси "Робот-шпион"

А Вам не кажется, что эти готовые большие платы не поместятся на шасси. Может лучше сделать самим плату управления (или взять arduino nano) и плату драйверов двигателей. Есть готовые варианты www.avrmicro.inf.ua

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/