26 #include <unordered_set>
32 default_random_engine generator(rd());
52 for (uint32_t m = 0; m < robotModes.size(); ++m) {
67 uint32_t numberOfPoints = pt(generator);
69 for (uint32_t p = fromPoint; p < fromPoint+numberOfPoints; ++p) {
74 double minPowerModeDelay = numeric_limits<double>::max();
76 minPowerModeDelay = min(minPowerModeDelay, m->minimalDelay());
79 throw runtime_error(
"Location::Location(...): Instance is infeasible due to power-save mode delays!");
81 mMinAbsDuration = max(mMinAbsDuration, minPowerModeDelay);
82 fromPoint += numberOfPoints;
93 vector<pair<uint32_t,uint32_t> > movements;
94 size_t s1 = fromActivity->locations().size();
95 size_t s2 = toActivity->locations().size();
97 for (uint32_t i = 0; i < s1; ++i)
98 for (uint32_t j = 0; j < s2; ++j)
99 movements.emplace_back(i,j);
101 shuffle(movements.begin(), movements.end(), generator);
102 vector<bool> fromCovered(s1,
false), toCovered(s2,
false);
104 for (
const auto& c : movements) {
105 Movement *mv =
new Movement(fromActivity->locations()[c.first]->point(), toActivity->locations()[c.second]->point(), par);
109 fromCovered[c.first] =
true;
110 toCovered[c.second] =
true;
112 if (count(fromCovered.cbegin(), fromCovered.cend(),
false) + count(toCovered.cbegin(), toCovered.cend(),
false) == 0)
116 fromActivity->addSuccessor(
this);
117 toActivity->addPredecessor(
this);
119 addSuccessor(toActivity);
120 addPredecessor(fromActivity);
128 Robot::Robot(uint32_t& fromActivityId, uint32_t& fromPointId,
const uint32_t& numberOfInputs,
129 const uint32_t& numberOfOutputs,
const ProjectParameters& par) : mParameters(par) {
131 uniform_int_distribution<uint32_t> psm(1u, (uint32_t) par.
minDelayOfModes.size());
133 uint32_t numberOfPowerSaveModes = psm(generator);
134 for (uint32_t m = 0; m < numberOfPowerSaveModes; ++m) {
144 vector<mCompositeBlock> operations;
145 uint32_t numberOfOperations = min(numberOfInputs, numberOfOutputs);
146 for (uint32_t op = 0; op+1 < numberOfOperations; ++op)
149 int32_t diffDeg = numberOfOutputs-numberOfInputs;
152 else if (diffDeg < 0)
159 for (uint32_t opOut = 0; opOut < operations.size(); ++opOut) {
160 for (uint32_t opIn = 0; opIn < operations.size(); ++opIn) {
162 connect(fromActivityId, operationsBlock, operations[opOut].out, operations[opIn].in);
167 connect(fromActivityId, operationsBlock, operationsBlock.out, {waitToNextCycle});
168 connect(fromActivityId, operationsBlock, {waitToNextCycle}, operationsBlock.in);
180 double sumOfDurations = 0.0;
181 size_t numberOfStatAct = 0;
182 vector<double> durationOfMovements;
184 if (a->type() != MOVEMENT) {
185 sumOfDurations += a->minAbsDuration();
188 durationOfMovements.push_back(a->minAbsDuration());
192 sort(durationOfMovements.begin(), durationOfMovements.end());
193 sumOfDurations += accumulate(durationOfMovements.begin(), durationOfMovements.begin()
194 + min(numberOfStatAct, durationOfMovements.size()), 0.0);
196 return sumOfDurations;
227 if (op ==
"assembly") {
230 }
else if (op ==
"disassembly") {
234 throw runtime_error(
"Robot::mCompositeBlock Robot::createComplexBlockHelper(...): Requested operation is not supported!");
241 connect(fromActivityId, block, block1.con2, block2.con1);
242 connect(fromActivityId, block, block2.con2, block3.con1);
250 uniform_int_distribution<uint32_t> sl(seqLength.from(), seqLength.to());
251 uniform_int_distribution<uint32_t> ns(numSeq.from(), numSeq.to());
254 uint32_t numberOfSequences = ns(generator);
256 function<void(StaticActivity*)> storeActivity = [&blockActivities](
StaticActivity *a) {
259 blockActivities.in.push_back(a);
262 blockActivities.w.push_back(a);
265 blockActivities.out.push_back(a);
270 for (uint32_t i = 0; i < numberOfSequences; ++i) {
272 uint32_t sequenceLength = sl(generator);
275 blockActivities.con1.push_back(op1);
279 for (uint32_t l = 0; l+2 < sequenceLength; ++l) {
282 blockActivities.w.push_back(op2);
283 blockActivities.mv.push_back(op2op);
287 if (sequenceLength == 1) {
291 throw runtime_error(
"Robot::mCompositeBlock Robot::createBlockOfOperations(...): "
292 "Sequence of unit length must have the same types of the first and last activity");
297 blockActivities.mv.push_back(op2op);
301 blockActivities.con2.push_back(op2);
304 connect(fromActivityId, blockActivities, blockActivities.con2, blockActivities.con1,
false);
306 return blockActivities;
309 void Robot::connect(uint32_t& fromActivityId,
mCompositeBlock& b,
const vector<StaticActivity*>& from,
const vector<StaticActivity*>& to,
bool fullyConnected)
const {
310 for (uint32_t i1 = 0; i1 < from.size(); ++i1) {
311 for (uint32_t i2 = 0; i2 < to.size(); ++i2) {
312 if (fullyConnected || i1 != i2) {
323 copy(b.in.cbegin(), b.in.cend(), back_inserter(ret.in));
324 copy(b.w.cbegin(), b.w.cend(), back_inserter(ret.w));
325 copy(b.out.cbegin(), b.out.cend(), back_inserter(ret.out));
326 copy(b.mv.cbegin(), b.mv.cend(), back_inserter(ret.mv));
341 uniform_real_distribution<double> handover(0.0, 100.0);
345 for (
Activity *succ : out->successors())
347 for (
Activity *succ : in->successors())
350 name(
"Inter-robot operation "+
numberToString(oid)+
" - bench handover");
355 for (
Activity *inSucc : in->successors()) {
356 for (
Activity *outSucc : out->successors()) {
357 mTimeLags.emplace_back(inSucc, outSucc, 0, 0);
358 mTimeLags.emplace_back(outSucc, inSucc, 0, 0);
362 name(
"Inter-robot operation "+
numberToString(oid)+
" - gripper-to-gripper handover");
372 if (sa1 ==
nullptr || sa2 ==
nullptr)
373 throw invalid_argument(
"void InterRobotOperation::generateSpatialCompatibilityPairs(...): Input activities must be static ones!");
375 vector<Location*> loc1 = sa1->locations(), loc2 = sa2->locations();
376 if (loc1.empty() || loc2.empty())
377 throw runtime_error(
"void InterRobotOperation::generateSpatialCompatibilityPairs(...): Static activity without interior locations!?");
380 vector<pair<uint32_t, uint32_t> > possibleLocPairs;
381 for (uint32_t i = 0; i < loc1.size(); ++i)
382 for (uint32_t j = 0; j < loc2.size(); ++j)
383 possibleLocPairs.emplace_back(i,j);
385 vector<bool> usedLoc1(loc1.size(),
false), usedLoc2(loc2.size(),
false);
386 shuffle(possibleLocPairs.begin(), possibleLocPairs.end(), generator);
388 for (
auto it = possibleLocPairs.cbegin(); it != possibleLocPairs.cend(); ++it) {
389 usedLoc1[it->first] = usedLoc2[it->second] =
true;
392 if (count(usedLoc1.begin(), usedLoc1.end(),
false) + count(usedLoc2.begin(), usedLoc2.end(),
false) == 0)
401 vector<pair<uint32_t, uint32_t> > possibleInterconnections;
404 for (uint32_t r1 = 0; r1 < nr; ++r1) {
405 for (uint32_t r2 = 0; r2 < nr; ++r2) {
406 if (r1 != r2 && r2 != 0 && r1+1 != nr)
407 possibleInterconnections.emplace_back(r1, r2);
411 uint32_t sumOfDegrees = 0;
412 shuffle(possibleInterconnections.begin(), possibleInterconnections.end(), generator);
413 double minimalAverageDegree = graphDeg(generator), averageDegree = 0.0, inf = numeric_limits<double>::infinity();
414 vector<vector<double> > distMatrix(nr, vector<double>(nr, inf));
416 for (
const auto& interconnection : possibleInterconnections) {
418 auto distMatrixCopy = distMatrix;
419 uint32_t r1 = interconnection.first, r2 = interconnection.second;
421 distMatrix[r1][r2] = 1.0;
423 for (uint32_t k : {r1, r2}) {
424 for (uint32_t i = 0; i < nr; ++i) {
425 for (uint32_t j = 0; j < nr; ++j) {
426 if (distMatrix[i][k]+distMatrix[k][j] < distMatrix[i][j])
427 distMatrix[i][j] = distMatrix[i][k]+distMatrix[k][j];
433 for (uint32_t i = 0; i < nr; ++i) {
434 if (distMatrix[i][i] < inf) {
442 distMatrix = distMatrixCopy;
446 bool connectedEnough =
true;
447 for (uint32_t r = 0; r < nr && connectedEnough; ++r) {
448 bool robotConnected =
false;
449 for (uint32_t rb = 0; rb < nr; ++rb) {
450 if (distMatrix[rb][r] < inf || r == 0) {
451 robotConnected =
true;
456 robotConnected = (distMatrix[r][nr-1] < inf || r+1 == nr) ? robotConnected :
false;
457 connectedEnough = (connectedEnough && robotConnected) ?
true :
false;
461 averageDegree = ((double) sumOfDegrees)/((double) nr);
463 if (connectedEnough ==
true && averageDegree >= minimalAverageDegree)
467 if (averageDegree < minimalAverageDegree) {
469 +
", obtained "+
numberToString(averageDegree)+
") cannot be reached.");
472 uint32_t fromActivityId = 0, fromPointId = 0;
473 for (uint32_t r1 = 0; r1 < nr; ++r1) {
474 uint32_t numberOfInputs = 0, numberOfOutputs = 0;
475 for (uint32_t r2 = 0; r2 < nr; ++r2) {
476 if (r1 != r2 && distMatrix[r1][r2] < inf)
478 if (r1 != r2 && distMatrix[r2][r1] < inf)
487 if (numberOfInputs == 0 || numberOfOutputs == 0)
488 throw runtime_error(
"RoboticLine::RoboticLine(...): Each robot has to have at least one input and one output activity!");
490 mRobots.push_back(
new Robot(fromActivityId, fromPointId, numberOfInputs, numberOfOutputs, par));
493 vector<vector<Activity*> > robotIn, robotOut;
494 for (uint32_t r = 0; r < nr; ++r) {
495 vector<Activity*> inActivities, outActivities;
496 vector<Activity*> activities =
mRobots[r]->activities();
497 copy_if(activities.cbegin(), activities.cend(), back_inserter(inActivities),
498 [](
Activity*
const& a) {
return (a->type() == IN ?
true :
false); });
499 copy_if(activities.cbegin(), activities.cend(), back_inserter(outActivities),
500 [](
Activity*
const& a) {
return (a->type() == OUT ?
true :
false); });
501 shuffle(inActivities.begin(), inActivities.end(), generator);
502 shuffle(outActivities.begin(), outActivities.end(), generator);
503 robotIn.push_back(inActivities); robotOut.push_back(outActivities);
507 for (uint32_t r1 = 0; r1 < nr; ++r1) {
508 for (uint32_t r2 = 0; r2 < nr; ++r2) {
509 if (r1 != r2 && distMatrix[r1][r2] < inf) {
510 vector<Activity*>& out = robotOut[r1], & in = robotIn[r2];
511 if (!out.empty() && !in.empty()) {
513 out.pop_back(); in.pop_back();
515 throw runtime_error(
"RoboticLine::RoboticLine(...): Not enough IN and OUT inter-robot activities!");
527 unordered_set<Pair> addedCollisions;
528 uint32_t numberOfGeneratedCollisions = 0, iter = 0;
529 uniform_int_distribution<uint32_t> robotId(0, par.
numberOfRobots-1);
532 const uint32_t desiredNumberOfCollisions = numCol(generator);
533 const uint32_t maxNumberOfIterations = 10*desiredNumberOfCollisions;
535 while (numberOfGeneratedCollisions < desiredNumberOfCollisions) {
537 uint32_t robotId1 = robotId(generator), robotId2 = robotId(generator);
539 if (robotId1 != robotId2) {
540 uniform_int_distribution<uint32_t> a1(0, ((int32_t)
mRobots[robotId1]->activities().size())-1);
541 uniform_int_distribution<uint32_t> a2(0, ((int32_t)
mRobots[robotId2]->activities().size())-1);
546 uniform_int_distribution<uint32_t> modeIdx1(0, ((int32_t) activity1->numberOfModes())-1);
547 uniform_int_distribution<uint32_t> modeIdx2(0, ((int32_t) activity2->numberOfModes())-1);
549 Pair collision = {activity1, modeIdx1(generator), activity2, modeIdx2(generator)};
551 if (addedCollisions.count(collision) == 0) {
553 addedCollisions.insert(collision);
554 ++numberOfGeneratedCollisions;
559 if (iter > maxNumberOfIterations) {
560 mWarnings.push_back(
"Cannot generate the requested number of collisions!");
569 double productionCycleTime = 0;
573 productionCycleTime = max(productionCycleTime, r->lowerBoundOfCycleTime());
The class represents the robot movement between two coordinates.
double mProductionCycleTime
The calculated production cycle time for *this robotic cell.
mCompositeBlock createBlockOfOperations(uint32_t &fromActivityId, uint32_t &fromPointId, const ActivityType &t1, const ActivityType &t2, const Interval< uint32_t > &numSeq, const Interval< uint32_t > &seqLength) const
It is a core method for the decomposition of the robot work to well-defined blocks.
Interval< double > dilatationFactor
Multiplicative factor by which the lower estimation of the cycle time will be adjusted.
Interval< uint32_t > numberOfPoints
The interval of the number of points (i.e. robot configurations) for each robot operation.
Auxiliary class encapsulating two activities to form collision or spatial compatibility pair...
Activity * mActivity2
Second activity.
void generateSpatialCompatibilityPairs(Activity *a1, Activity *a2)
It is an auxiliary method for the constructor that helps to generate the compatibility pairs...
The base class incorporating common properties for robot operations and movements.
The structure with desired properties for the generated instances.
std::vector< Interval< double > > minDelayOfModes
The time interval of minimal duration for each power saving mode.
Instance of the class includes all the data structures and methods related to a robot.
Location(const uint32_t &point, const std::vector< RobotPowerMode * > &robotModes, const ProjectParameters &par)
It constructs the object representing a location of an operation from the robot point of view...
bool operator==(const Pair &p) const
It compares two Pair data-structures and returns the result of comparison.
std::vector< InterRobotOperation > mInterRobotOperations
Inter-robot operations for a weldment/workpiece passing.
std::vector< Location * > mLocations
The collection of possible robot configurations, i.e. locations, for this operation.
~Robot()
It frees the memory occupied by dynamically allocated activities and power saving modes...
std::vector< Interval< double > > energyFunctionCoefficients
Intervals of energy function coefficients.
Collection of movements between two static activities.
void generateCollisions(const ProjectParameters &par)
It generates collisions between robots.
Interval< int32_t > degreeOfCoefficients
The degree of coefficients, e.g. results to where are energy function coefficients.
ProjectParameters mParameters
Desired properties of generated instances defined in the input configuration file.
std::vector< RobotPowerMode * > mRobotModes
Available power saving modes for this robot.
std::vector< std::string > mWarnings
Warnings produced during the generation of this robotic cell. Written to the console later to not mix...
std::vector< Pair > mCollisions
Collisions between robots.
std::vector< Robot * > mRobots
Robots incorporated in the robotic cell.
uint32_t mMode2
The mode of the second activity, i.e. a movement or location identification.
InterRobotOperation(uint32_t oid, Activity *out, Activity *in, const ProjectParameters &par)
It creates the inter-robot operation according the desired parameters stated in ProjectParameters dat...
virtual ~DynamicActivity() override
It frees the memory occupied by dynamically allocated movements.
Interval< double > minimalVertexDegree
The interval of the desired average node degree for the graph of robot interconnections.
Movement(const uint32_t &from, const uint32_t &to, const ProjectParameters &par)
The constructor creates the movement according to the desired properties given in the project configu...
virtual ~StaticActivity() override
It frees the memory occupied by dynamically allocated locations.
std::vector< Interval< double > > inputPowerOfModes
For each power saving mode of the robot the interval of input power is defined.
Collection of locations in which a robot operation can be performed.
Interval< double > prolongationOfOperation
The time interval of the additive part to the minimal operation duration.
~RoboticLine()
It frees all the memory occupied by robots.
It represents the power saving mode of the robot.
double mMaxAbsDuration
The maximal absolute duration of the activity to remain feasible.
double mMinDuration
The minimal possible duration of the robot movement.
StaticActivity(const uint32_t &aid, uint32_t &fromPoint, const ActivityType &type, const std::vector< RobotPowerMode * > &robotModes, const ProjectParameters &par)
It generates the static activity, i.e. robot operation, according to the configuration.
The structure containing the activities in a block.
Interval< uint32_t > numberOfCollisions
The interval of the number of generated collisions between robots.
void connect(uint32_t &fromActivityId, mCompositeBlock &b, const std::vector< StaticActivity * > &from, const std::vector< StaticActivity * > &to, bool fullyConnected=true) const
It interconnects two sub-blocks and adds the generated dynamic activities to the block b...
double percentageOfTableHandover
The probability that the workpiece/weldment is handed over to other robot by using a bench...
Activity * mActivity1
First activity.
Interval< double > prolongationOfMovement
The interval of prolongation for the fastest robot movements.
std::vector< LocationDependentPowerConsumption > mLocationDependentPowerConsumption
It defines the power consumption for the robot power saving modes that input power is dependent on th...
Robot(uint32_t &fromActivityId, uint32_t &fromPointId, const uint32_t &numberOfInputs, const uint32_t &numberOfOutputs, const ProjectParameters &par)
It constructs the robot according to the desired parameters.
mCompositeBlock createDisassemblyBlock(uint32_t &fromActivityId, uint32_t &fromPointId, const uint32_t &numberOfOutputs) const
It creates a block composed of disassembling/cutting the workpiece and taking its parts to other robo...
mCompositeBlock createComplexBlockHelper(uint32_t &fromActivityId, uint32_t &fromPointId, const uint32_t &numberOfSeq, const std::string &op) const
It is an auxiliary method wrapping complex calls to createBlockOfOperations method.
LocationDependentPowerConsumption(RobotPowerMode *mode, const uint32_t &modeIdx, const ProjectParameters &par)
It constructs the object encapsulating the information about the input power for the given robot conf...
double mMaxDuration
The maximal duration of the movement.
Interval< uint32_t > sequenceLength
The interval of the number of robot sub-operations for each atomic sequence.
Interval< double > minDurationOfOperation
The interval of minimal duration of the robot operation, e.g. welding, assembling, ...
std::vector< Monomial > mEnergyFunction
double mInputPower
Input power of the robot for a given robot configuration, see also the Location class.
mCompositeBlock mergeBlocks(const std::vector< mCompositeBlock > &blocks) const
It copies the activities (their pointers) in blocks to the one composite block.
mCompositeBlock createAssemblyBlock(uint32_t &fromActivityId, uint32_t &fromPointId, const uint32_t &numberOfInputs) const
It creates a block composed of gathering required parts to a bench and their assembly/welding to one ...
Interval< uint32_t > numberOfSequences
The interval of the number of atomic sequences in each (dis)assembling/welding/cutting operation...
double mMinAbsDuration
The minimal absolute duration of the activity to remain feasible.
It represents the location of robotic work.
std::vector< Activity * > mActivities
A collection of activities belonging to the robot.
mCompositeBlock createSerialSequence(uint32_t &fromActivityId, uint32_t &fromPointId) const
The method creates a block of a fixed sequence of operations, e.g. welding, cutting, without alternatives and updates the identification values.
The file contains various classes devoted to abstract representation of the robotic cell...
std::string numberToString(const T &number)
It converts the number to string.
void calculateProductionCycleTime(const ProjectParameters &par)
It calculates production cycle time with respect to the desired dilatation factor.
double lowerBoundOfCycleTime() const
The method calculates an estimation of cycle time.
std::vector< Pair > mSpatialCompatibility
Spatial compatibility pairs, i.e. a handover takes place at the right location for both involved robo...
uint32_t numberOfRobots
The number of robots in the robotic cell.
RoboticLine(const ProjectParameters &par)
It generates all the required data-structures for the robotic cell, i.e. an instance of a robotic cel...
uint32_t mMode1
The mode of the first activity, i.e. a movement or location identification.
std::vector< Movement * > mMovements
The collection of movements between two static activities.
Interval< double > minDurationOfMovement
The interval of minimal duration of robot movements (defines the fastest movement).
DynamicActivity(const uint32_t &aid, StaticActivity *fromActivity, StaticActivity *toActivity, const ProjectParameters &par)
It generates the dynamic activity with respect to the desired properties.
std::vector< TimeLag > mTimeLags
Time lags ensuring the correct time synchronization between robots.