Первая тестируемая на ПЛК версия

This commit is contained in:
VladislavOstapov 2023-01-28 12:12:01 +03:00
parent 14b5cdf06d
commit d8fee17444
4 changed files with 198 additions and 111 deletions

View File

@ -344,9 +344,9 @@ int main() {
} }
robot_main(); robot_main();
// scheduler_main(); scheduler_main();
increment_zone(ROBOT_ZONE_GAL); // increment_zone(ROBOT_ZONE_GAL);
increment_zone(ROBOT_ZONE_ETCH); // increment_zone(ROBOT_ZONE_ETCH);
send_str("\033c"); send_str("\033c");
showAll(); showAll();

View File

@ -101,8 +101,8 @@ static void emulate_robot(robot_code &code, robot_regs& r, char robot_id) {
case ROBOT_CMD_UP_code: case ROBOT_CMD_UP_code:
if (code.barrel_id >= 0 && cmd_arg) { if (code.barrel_id >= 0 && cmd_arg) {
// не давать ехать перед тем как истечет таймер // не давать ехать перед тем как истечет таймер (только для не пустых барабанов)
if (barrels[code.barrel_id].software_timer > 0) { if (!barrels[code.barrel_id].flags.is_empty && barrels[code.barrel_id].software_timer > 0) {
break; break;
} }
barrels[code.barrel_id].flags.is_up = true; barrels[code.barrel_id].flags.is_up = true;

View File

@ -122,6 +122,14 @@ void scheduler_main()
} }
} }
// автоматический инкремент зон травления и цинкования
if (etching_zone < 0) {
increment_zone(ROBOT_ZONE_ETCH);
}
if (galvanizing_zone < 0) {
increment_zone(ROBOT_ZONE_GAL);
}
// кнопки на линии // кнопки на линии
// кнопка загрузки барабана // кнопка загрузки барабана
@ -222,21 +230,28 @@ void scheduler_main()
// для каждого робота нужно получить свой список задач // для каждого робота нужно получить свой список задач
// и надо еще сделать так, чтобы роботы не столкнулись // и надо еще сделать так, чтобы роботы не столкнулись
// суть этого предела в том, чтобы робот всегда был свободен ЗА зоной gal8,
// но при этом если зоной обмена выбрана промывка 3а, то за ней тоже, получается max(ZONE_G8, exchange_zone)
const short robot1_border = ZONE_GALVANIZING_8 > hla_exchange_zone ? ZONE_GALVANIZING_8 : hla_exchange_zone;
// суть этого предела в том, чтобы робот всегда держал свободной зону gal1,
// но при этом если зоной обмена выбрана промывка 2б, то за ней тоже, получается min(ZONE_G1, exchange_zone)
const short robot2_border = ZONE_GALVANIZING_1 < hla_exchange_zone ? ZONE_GALVANIZING_1 : hla_exchange_zone;
// логика для того, чтобы роботы не столкнулись в начале // логика для того, чтобы роботы не столкнулись в начале
if (robot1.dx.current_zone < ZONE_GALVANIZING_1) { if (robot1.dx.current_zone < robot1_border) {
// начальная позиция робота 1 - промывка 3Б
robot2_lock_zone = -1; robot2_lock_zone = -1;
robot1_lock_zone = ZONE_WASHING_3B; robot1_lock_zone = robot1_border;
if (robot1_code.PC < 0) { if (robot1_code.PC < 0) {
robot1_code.barrel_id = -1; robot1_code.barrel_id = -1;
robot1_code.code[0] = ROBOT_CMD_DOWN(); robot1_code.code[0] = ROBOT_CMD_DOWN();
robot1_code.code[1] = ROBOT_CMD_MOVE_TO_ZONE(ZONE_WASHING_3B); robot1_code.code[1] = ROBOT_CMD_MOVE_TO_ZONE(robot1_border + 2);
robot1_code.code[2] = ROBOT_CMD_END(); robot1_code.code[2] = ROBOT_CMD_END();
robot1_code.PC = 0; robot1_code.PC = 0;
} }
} else if (robot2.dx.current_zone < ZONE_DEGREASING) { } else if (robot2.dx.current_zone < ZONE_DEGREASING) {
// начальная позиция робота 1 - обезжир // начальная позиция робота 1 - обезжир
robot2_lock_zone = ZONE_WASHING_2A; robot2_lock_zone = ZONE_DEGREASING;
if (robot2_code.PC < 0) { if (robot2_code.PC < 0) {
robot2_code.barrel_id = -1; robot2_code.barrel_id = -1;
robot2_code.code[0] = ROBOT_CMD_DOWN(); robot2_code.code[0] = ROBOT_CMD_DOWN();
@ -244,6 +259,16 @@ void scheduler_main()
robot2_code.code[2] = ROBOT_CMD_END(); robot2_code.code[2] = ROBOT_CMD_END();
robot2_code.PC = 0; robot2_code.PC = 0;
} }
} else if (robot2.dx.current_zone > robot2_border) {
// это уже граница робота 2
robot2_lock_zone = robot2_border - 2;
if (robot2_code.PC < 0) {
robot2_code.barrel_id = -1;
robot2_code.code[0] = ROBOT_CMD_DOWN();
robot2_code.code[1] = ROBOT_CMD_MOVE_TO_ZONE(robot2_border - 2);
robot2_code.code[2] = ROBOT_CMD_END();
robot2_code.PC = 0;
}
} else { } else {
// отдельно просчитаем все для первого робота // отдельно просчитаем все для первого робота
if (robot1_code.PC < 0) { if (robot1_code.PC < 0) {

264
utils.c
View File

@ -33,10 +33,18 @@ char zone_is_busy(short zone) {
short get_first_night_zone() { short get_first_night_zone() {
// TODO сделать корректное вычисление ночной зоны
// всего зон, куда можно сныкать барабаны (всего 9 мест: 8 промывок и выгрузка) // всего зон, куда можно сныкать барабаны (всего 9 мест: 8 промывок и выгрузка)
for (short i = 0; i < 9; i++) { for (short nz = 0; nz < 9; nz++) {
if (!zone_is_busy(NIGHT_ZONES[i])) { char found = 0;
return NIGHT_ZONES[i]; for (short i = 0; i < BARRELS_COUNT; i++) {
if (barrels[i].flags.is_exist && barrels[i].zone == NIGHT_ZONES[nz] && !barrels[i].flags.is_night) {
found = 1;
}
}
if (found == 0) {
return NIGHT_ZONES[nz];
} }
} }
@ -47,108 +55,121 @@ short get_first_night_zone() {
short _get_dest_zone(struct barrel *bar) { short _get_dest_zone(struct barrel *bar) {
if (bar->flags.is_night) { if (bar->flags.is_night) {
return ZONE_LOAD_1; return ZONE_LOAD_1;
} else { }
switch (bar->zone) {
case ZONE_LOAD_2:
// загрузка 2, только в нее можно грузить новые барабаны, нужно обезжиривание
return ZONE_DEGREASING;
case ZONE_DEGREASING: // если это зона обмена и барабан пустой
// обезжиривание, нужна промывка 1А if (bar->zone == hla_exchange_zone && bar->flags.is_empty) {
return ZONE_WASHING_1A; return ZONE_LOAD_1;
}
case ZONE_WASHING_1A: switch (bar->zone) {
// промывка 1А, нужна промывка 1Б case ZONE_LOAD_2:
return ZONE_WASHING_1B; // загрузка 2, только в нее можно грузить новые барабаны, нужно обезжиривание
return ZONE_DEGREASING;
case ZONE_WASHING_1B: case ZONE_DEGREASING:
// промывка 1Б, нужно травление (зоны 5-6) // обезжиривание, нужна промывка 1А
if (etching_zone < 0) { return ZONE_WASHING_1A;
return -1;
}
return (short)(ZONE_ETCHING_1 + etching_zone);
case ZONE_ETCHING_1: case ZONE_WASHING_1A:
case ZONE_ETCHING_2: // промывка 1А, нужна промывка 1Б
// травление, нужна промывка 2А return ZONE_WASHING_1B;
return ZONE_WASHING_2A;
case ZONE_WASHING_2A: case ZONE_WASHING_1B:
// промывка 2А, нужна промывка 2Б // промывка 1Б, нужно травление (зоны 5-6)
return ZONE_WASHING_2B; if (etching_zone < 0) {
return -1;
}
return (short)(ZONE_ETCHING_1 + etching_zone);
case ZONE_WASHING_2B: case ZONE_ETCHING_1:
// промывка 2Б, нужно цинкование (зоны 9-16) case ZONE_ETCHING_2:
if (galvanizing_zone < 0) { // травление, нужна промывка 2А
return -1; return ZONE_WASHING_2A;
}
return (short)(ZONE_GALVANIZING_1 + galvanizing_zone);
case ZONE_GALVANIZING_1: case ZONE_WASHING_2A:
case ZONE_GALVANIZING_2: // промывка 2А, нужна промывка 2Б
case ZONE_GALVANIZING_3: return ZONE_WASHING_2B;
case ZONE_GALVANIZING_4:
case ZONE_GALVANIZING_5: case ZONE_WASHING_2B:
case ZONE_GALVANIZING_6: // промывка 2Б, нужно цинкование (зоны 9-16)
case ZONE_GALVANIZING_7: if (galvanizing_zone < 0) {
case ZONE_GALVANIZING_8: return -1;
// TODO перенести эту логику в функцию can_move }
// цинкование, требуется чтобы в зонах 17-22 было максимум 2 барабана (3 барабана для этой части линии - максимум) return (short)(ZONE_GALVANIZING_1 + galvanizing_zone);
if (!zone_is_busy(ZONE_WASHING_3A)) {
short count = 0; case ZONE_GALVANIZING_1:
// если зона 17 свободна, то диапазон начнется с case ZONE_GALVANIZING_2:
for (short i = ZONE_WASHING_3B; i <= (short)ZONE_UNLOAD; i++) { case ZONE_GALVANIZING_3:
if (zone_is_busy(i)) { case ZONE_GALVANIZING_4:
count++; case ZONE_GALVANIZING_5:
} case ZONE_GALVANIZING_6:
} case ZONE_GALVANIZING_7:
if (count < 3) { case ZONE_GALVANIZING_8:
return ZONE_WASHING_3A; // цинкование, требуется чтобы в зонах 17-22 было максимум 2 барабана (3 барабана для этой части линии - максимум)
if (!zone_is_busy(ZONE_WASHING_3A)) {
short count = 0;
// если зона 17 свободна, то диапазон начнется с
for (short i = ZONE_WASHING_3B; i <= (short)ZONE_UNLOAD; i++) {
if (zone_is_busy(i)) {
count++;
} }
} }
return -1; if (count < 3) {
return ZONE_WASHING_3A;
case ZONE_WASHING_3A:
// промывка 3А, перекладываем в промывку 3Б
return ZONE_WASHING_3B;
case ZONE_WASHING_3B:
// это перед пассивацией, требует свободную промывку 4А и на всякий случай свободную пассивацию
if (!zone_is_busy(ZONE_WASHING_4A)) {
return ZONE_PASSIVATION;
} }
// это атомарная операция, по идее вносить барабан в пассивацию нельзя }
return -1;
case ZONE_WASHING_3A:
// промывка 3А, перекладываем в промывку 3Б
return ZONE_WASHING_3B;
case ZONE_WASHING_3B:
// это перед пассивацией, требует свободную промывку 4А и на всякий случай свободную пассивацию
if (!zone_is_busy(ZONE_WASHING_4A)) {
return ZONE_PASSIVATION;
}
// это атомарная операция, по идее вносить барабан в пассивацию нельзя
return -1;
case ZONE_PASSIVATION:
// процесс пассивации, нужна промывка 4A
// чисто теоретически сюда никогда не попадем, но если вдруг выстрелит пусть будет
return ZONE_WASHING_4A;
case ZONE_WASHING_4A:
// промывка 4А, перекладываем в промывку 4Б
return ZONE_WASHING_4B;
case ZONE_WASHING_4B:
// последняя промывка в процессе
if (hla_night_mode) {
// TODO изменить логику для ночного режима
return -1; return -1;
} else {
return ZONE_UNLOAD;
}
case ZONE_PASSIVATION: case ZONE_UNLOAD:
// процесс пассивации, нужна промывка 4A // последняя промывка, нужно разрешение на выгрузку
// чисто теоретически сюда никогда не попадем, но если вдруг выстрелит пусть будет if (button_unload) {
return ZONE_WASHING_4A;
case ZONE_WASHING_4A:
// промывка 4А, перекладываем в промывку 4Б
return ZONE_WASHING_4B;
case ZONE_WASHING_4B:
// последняя промывка в процессе
if (hla_night_mode) { if (hla_night_mode) {
// TODO изменить логику для ночного режима
return -1;
} else {
return ZONE_UNLOAD;
}
case ZONE_UNLOAD:
// последняя промывка, нужно разрешение на выгрузку
if (button_unload) {
if (one_robot_mode) { if (one_robot_mode) {
return ZONE_LOAD_1; return ZONE_LOAD_1;
} else { } else {
return hla_exchange_zone; return hla_exchange_zone;
} }
} else {
short nz = get_first_night_zone();
if (nz < hla_exchange_zone) {
return hla_exchange_zone;
} else {
return nz;
}
} }
break; }
} break;
} }
return -1; return -1;
@ -160,38 +181,64 @@ short can_move(struct barrel *bar, char robot_id) {
if (robot_id != 1 && robot_id != 2) { if (robot_id != 1 && robot_id != 2) {
return -3; return -3;
} }
// сразу отсекаем варианты, при которых невозможно переместить барабан // сразу отсекаем варианты, при которых невозможно переместить барабан
if (!bar->flags.is_exist) { if (!bar->flags.is_exist) {
return -3; return -3;
} }
if (bar->software_timer > 0) {
return -2;
}
if (bar->flags.robot != 0) { if (bar->flags.robot != 0) {
return -3; return -3;
} }
// проверка ночного режима // проверка ночного режима
if (hla_night_mode) { if (hla_night_mode) {
if (bar->flags.is_night && !bar->flags.is_empty) { if (bar->flags.is_night) {
return -1; return -1;
} }
} }
// тут просчет примерного времени, в течении которого можно доехать до барабана
if (!bar->flags.is_empty) {
short approximate_time;
if (robot_id == 1) {
approximate_time = bar->zone - robot1.dx.current_zone;
} else {
approximate_time = bar->zone - robot1.dx.current_zone;
}
// abs(approximate_time)
if (approximate_time < 0) {
approximate_time = -approximate_time;
}
#ifndef EMULATOR
approximate_time *= 4;
#endif
if (bar->software_timer > -approximate_time) {
return -2;
}
}
// дальше нужно проверить, что можно передвигать бочку // дальше нужно проверить, что можно передвигать бочку
short dest_zone = _get_dest_zone(bar); short dest_zone = _get_dest_zone(bar);
if (zone_is_busy(dest_zone)) {
return -1;
}
if (!one_robot_mode && dest_zone >= 0) { if (!one_robot_mode && dest_zone >= 0) {
if (robot_id == 1) { if (robot_id == 1) {
// если робот 1, то это старый, который ближе к концу линнии. // если робот 1, то это старый, который ближе к концу линнии.
// Ему нельзя ехать если хоть одна из зон <= max(r2_pos, r2_lock) + кол-во пограничных зон // Ему нельзя ехать если хоть одна из зон <= max(r2_pos, r2_lock) + кол-во пограничных зон
short border = robot2.dx.current_zone; short border = robot2.dx.current_zone;
if (robot2_lock_zone > border) { if (border < robot2_lock_zone) {
border = robot2_lock_zone; border = robot2_lock_zone;
} }
if (border < ZONE_WASHING_2A) {
border = ZONE_WASHING_2A;
}
border += LOCK_ZONE_BORDER; border += LOCK_ZONE_BORDER;
if (bar->zone <= border || dest_zone <= border) { if (bar->zone <= border || dest_zone <= border) {
@ -201,9 +248,13 @@ short can_move(struct barrel *bar, char robot_id) {
// если робот 2, то это новый, который ближе к началу линнии. // если робот 2, то это новый, который ближе к началу линнии.
// Ему нельзя ехать если хоть одна из зон >= max(r2_pos, r2_lock) - кол-во пограничных зон // Ему нельзя ехать если хоть одна из зон >= max(r2_pos, r2_lock) - кол-во пограничных зон
short border = robot1.dx.current_zone; short border = robot1.dx.current_zone;
if (robot1_lock_zone < border) { if (border > robot1_lock_zone) {
border = robot1_lock_zone; border = robot1_lock_zone;
} }
if (border > ZONE_WASHING_3B) {
border = ZONE_WASHING_3B;
}
border -= LOCK_ZONE_BORDER; border -= LOCK_ZONE_BORDER;
if (bar->zone >= border || dest_zone >= border) { if (bar->zone >= border || dest_zone >= border) {
@ -435,6 +486,9 @@ void create_operation(struct robot_code *code, short barrel_id, const short star
if (barrel_id >= 0) { if (barrel_id >= 0) {
barrels[barrel_id].flags.robot = robot_id; barrels[barrel_id].flags.robot = robot_id;
if (hla_night_mode && barrels[barrel_id].flags.is_empty && dest_zone == get_first_night_zone()) {
barrels[barrel_id].flags.is_night = -1;
}
} }
short cmd_index = 0; short cmd_index = 0;
@ -653,19 +707,27 @@ void create_operation(struct robot_code *code, short barrel_id, const short star
if (!one_robot_mode && !hla_night_mode) { if (!one_robot_mode && !hla_night_mode) {
if (robot_id == 2) { if (robot_id == 2) {
if (dest_zone >= ZONE_GALVANIZING_1) { // суть этого предела в том, чтобы робот всегда держал свободной зону gal1,
// но при этом если зоной обмена выбрана промывка 2б, то за ней тоже, получается min(ZONE_G1, exchange_zone)
const short robot2_border = (ZONE_GALVANIZING_1 < hla_exchange_zone ? ZONE_GALVANIZING_1 : hla_exchange_zone) - 1;
if (dest_zone >= robot2_border) {
// из промывки 2б он перекладывал, пусть едет в промывку 2а // из промывки 2б он перекладывал, пусть едет в промывку 2а
code->code[cmd_index++] = ROBOT_CMD_SET_LOCK_ZONE(ZONE_WASHING_2A); code->code[cmd_index++] = ROBOT_CMD_SET_LOCK_ZONE(robot2_border - 1);
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(ZONE_WASHING_2A); code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(robot2_border - 1);
} else if (dest_zone < ZONE_DEGREASING) { } else if (dest_zone < ZONE_DEGREASING) {
code->code[cmd_index++] = ROBOT_CMD_SET_LOCK_ZONE(ZONE_DEGREASING); // code->code[cmd_index++] = ROBOT_CMD_SET_LOCK_ZONE(ZONE_DEGREASING);
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(ZONE_DEGREASING); code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(ZONE_DEGREASING);
} }
} else if (robot_id == 1) { } else if (robot_id == 1) {
if (dest_zone <= ZONE_WASHING_3A) { // суть этого предела в том, чтобы робот всегда был свободен ЗА зоной gal8,
// но при этом если зоной обмена выбрана промывка 3а, то за ней тоже, получается max(ZONE_G8, exchange_zone)
const short robot1_border = (ZONE_GALVANIZING_8 > hla_exchange_zone ? ZONE_GALVANIZING_8 : hla_exchange_zone) + 1;
if (dest_zone <= robot1_border) {
// чтобы из этой зоны можно было переложить барабан первому роботу // чтобы из этой зоны можно было переложить барабан первому роботу
code->code[cmd_index++] = ROBOT_CMD_SET_LOCK_ZONE(ZONE_WASHING_4A); // code->code[cmd_index++] = ROBOT_CMD_SET_LOCK_ZONE(robot1_border + 1);
code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(ZONE_WASHING_4A); code->code[cmd_index++] = ROBOT_CMD_MOVE_TO_ZONE(robot1_border + 1);
} }
} }
} }