Geo-Ron / AzuritBer

Ardumower full odometry version
0 stars 0 forks source link

Consideration: Major code rewrite for AzuritBer to simplify and improve functionality #3

Open Geo-Ron opened 3 years ago

Geo-Ron commented 3 years ago

I have spend the last week going through your code and I am really impressed on the motor control with odometry. I do not fully grasp the inner workings of the PID controller and some of the calculations you make, but that will come eventually 😉

I have seen that it has become a really complex state-machine, because of the old Azurit code remains and that you have created a new state for every operation/target. In my opinion this makes everything over-complex and hard to improve.

I am proposing a new/revised way of coding the Ardumower, that I want to contribute to your current code.

I would like to know your point of view on this method and would really like to accomplish this together, instead of creating my own standalone fork of your code. So please reply here and discuss.

Change the way the states are used

My thoughts would be that we use the following items:

In the code it would be wise (to my opinion) to honour the following rules:

My recommendations on the state improvements would be the following

States (these would be the actual action the robot is doing; the outputs)

Statuses (what major job am I doing)

Task (current task/substatus)

This task would consist of a few predefined STATES.

For example, avoid obstacle would be reverse, roll x degrees, circles around it for x meter, roll back to original heading and resume status.

You have to think about the states the other way around.

The used of only technical machine states instead of functional will reduced the amount of code that needs to be maintained because of less duplicate code.

A few examples:

- Job/Status: NORMAL_MOWING
  - Task: DRIVE
  - Machine state: FORWARD

- Job/Status: NORMAL_MOWING
  - Task: TURN (because of perimeter reached, while mowing random)
  - Machine state: STOP_ROLLOUT, then DRIVE_BACKWARDS, then ROLL for random°, then DRIVE

- Job/Status: NORMAL_MOWING
  - Task: TURN (because of perimeter reached, while mowing lanes)
  - Machine state: STOP_ROLLOUT, then DRIVE_BACKWARDS, then ROLL for 135°, then DRIVE 20cm, then ROLL for 45°, then DRIVE

- Job/Status: NORMAL_MOWING
  - Task: AVOID_OBSTACLE (because of bumper or sonar triggered)
  - Machine state: STOP_HARD, then DRIVE_BACKWARDS, then ROLL for 45°, then CIRCLE around is, then ROLL to original heading, then DRIVE

- Job/Status: BACK_TO_STATION
  - Task: PERI_FIND
  - Machine state: ROLL to find strongest PERIMETER heading (or to set GPS coördinates), then DRIVE untill perimeter OUTSIDE

- Job/Status: BACK_TO_STATION
  - Task: PERI_TRACK
  - Machine state: ROLL to get Perimeter INSIDE, then PERI_TRACK untill found station by chgVoltage

I know you have abandoned the GPS usage, but I would like to use it for a fast_track to go back to station. Only a first drive heading to find the perimeter.

A DEV branch would be a good idea.

Geo-Ron commented 2 years ago

Implementatie:

Task wordt een nieuw array met de volgende state objecten (struct) met de volgende velden:

Deze array met states in een Task wordt aan het begin gevuld (setNewTask) Wanneer een state klaar is in een task, wordt Result=Success en kan setNewState de volgende staat beginnen. Deze wordt aangeroepen via getNewState.

Bij Result=Failure wordt ActualDistance gevuld, en een rollBack gestart op basis van deze data.

Dus:

newStatus change to NORMALMOW

  1. setNewTask -> resultaat: Drive, want geen trigger voor andere actie
  2. requestNextState -> FORWARD: SpeedWheelLeft = SpeedWheelRight = maxPWM
  3. state FORWARD zal accelereren als de PWM < dan beoogd

bumperLeft triggered (in state routine)

  1. setNewState: STOP_HARD
  2. setNewTask -> resultaat: OBSTACLE_AVOID, want trigger bumperLeft
  3. setNewTask -> array tasks met states wordt gevuld:
    • reverse 10 cm
    • rotate 90deg right (want bumper links),
    • drive arc of 1m (calculate wheel speed and distance based on robot dimensions),
    • rotate 90 deg right.
  4. setNewTask start state via setNewState op index 0, via var currStatefromTask
  5. loop op currTask bij success zet tasks[currIndex].Result = Success bij afleggen van de gedefinieerde afstand en roept requestNextState aan met tasks[currStatefromTask]
  6. requestNextState hoogt currStatefromTask op met 1 bij success en stuurt dit naar setNextState
    • requestNextState start rollBack bij Failure, door aanroepen van huidige state naar setNewTask met boolean rollBack
    • setNewTask met rollback wordt speed en distance *-1 gedaan
    • aan einde gaat setNewTask weer naar requestNextState met rolledBack boolean
    • rolledBack boolean maakt retry met grotere arc diameter en retry = 1

Obstacle wordt ook een nieuw object (struct) om in kaart te brengen op basis van behaalde resultaten

Obstacle:

Met het obstacle kan bepaald worden of de linker bumper (bijvoorbeeld) deze ontdekt heeft. Dan kan met een obstacle_read ook gekeken worden of rechts ook een object te vinden is. Afhankelijk van de input kan worden bepaald wat de actie is.

Voorbeeld: