Swarm Robotics
 
Notifications
Clear all

Swarm Robotics

85 Posts
7 Users
30 Reactions
28.5 K Views
(@davee)
Member
Joined: 5 years ago
Posts: 2043
 

Hi @thrandell,

Re: I anticipated the detection area would increase with the duty cycle, but instead it’s more of a bell curve.  Clearly demonstrating my lack of understanding of how PWM and the receiver work.

Sorry, I haven't taken the time to carefully follow your thread, but I assume your experiment producing the bell curve is based on Vishay TSAL6400 LED and TSSP58038 IR receiver (not the Sharp device).

I didn't see much description of your software or hardware, so the following conjectures are also based on guesses ... hence they may be useful or irrelevant ... I'll leave you to judge. 🙄 

A quick scan of the datasheets for Vishay TSAL6400 LED and TSSP58038 IR receiver suggested:

  • LED is just a 'simple LED' ... no electronics built in ... light will directly related to the applied voltage/current
  • IR receiver ... not just a photodiode, but a 'mini-system' with amplifier, band pass filter, etc.

From the data sheet: https://docs.rs-online.com/0aa8/0900766b8118041d.pdf

image

You mention PWM, but not frequency, etc., or what is doing/required for.

The IR receiver includes a bandpass filter centred on 38 kHz ... that is, it is trying to measure the intensity of light which is being modulated at 38 kHz, and rejecting everything else.

As the LED does not contain any circuitry to modulate the light, I guess your PWM frequency is 38kHz, effectively switching the LED light production on and off at 38kHz.

Oversimplistically, I am guessing the 'raw' (internal) signal picked up by the photodiode is a square wave, and that you are changing its mark-space ratio in your test that yields a bell-shaped curve.

The Fourier transform of a square wave with 1:1 mark-space (e.g. see ref https://mathworld.wolfram.com/FourierSeriesSquareWave.html) is the sum of sine waves based on the fundamental square wave frequency and its odd harmonics. From the same reference:

image
image

Hence passing this waveform through a bandpass filter centred on the fundamental frequency, will allow the fundamental frequency sine wave to pass through and attenuate the harmonics .. possibly to the extent that only the fundamental frequency sine wave passes through with a significant ampltitude.

To properly evaluate the effect of changing the mark-space ratio, I suggest an investigation with a Fourier transform software program ... but I will just offer a guess that deviating from 1:1 will reduce the effective amplitude of the fundamental frequency component.

I should emphasise, the last statement is only a guess, but sorry, I don't have the time to do the experiment (or to analyse the maths) suggested. Maybe you would like to look into it and report back?

Best wishes, Dave



   
robotBuilder reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 7 years ago
Posts: 2508
 

@davee 

I didn't see much description of your software or hardware, so the following conjectures are also based on guesses ... hence they may be useful or irrelevant ... I'll leave you to judge. 🙄 

Which was the problem I was having not really knowing enough about the setup to guess an answer.

Thank you for making the effort to try and work it out.  It has been a long long time since I last read a little book I once bought explaining op amp theory and practice.

 



   
DaveE reacted
ReplyQuote
THRandell
(@thrandell)
Brain Donor
Joined: 5 years ago
Posts: 311
Topic starter  
Posted by: @zander
Is it April 1 somewhere? Cut their legs off and glued onto others, really?

Ron,

Look what I came across today.  Odometry and insect navigation  Check out figure 4, a cruel experiment to be sure.

 

Tom


To err is human.
To really foul up, use a computer.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 6 years ago
Posts: 8047
 

@thrandell OUCH!


First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
THRandell
(@thrandell)
Brain Donor
Joined: 5 years ago
Posts: 311
Topic starter  

Well I finished a second prototype.  This one is smaller with different motors, cheaper sensors, and a different MCU.

IMG 2303

The design grew from trying to fit everything within a 3.25” diameter, the size of the prototype board that holds the sensors

IMG 2167

The MCU is a Raspberry Pi Pico and it sits between the sensors and the top bit that holds 3 small LEDs and a photo transistor

IMG 2300

In the requirements doc I put together for swarm robots (it’s actually more of a wishlist) I have a section for sensing and signaling with these five items:

  1. minimal interference among robots
  2. kin-detection
  3. interference from environmental factors
  4. stigmergic sensing and signaling
  5. generic sensing

 

I’ve been working up a way for the robots to signal each other via the IR emitter and receiver, and the same sensors work well for obstacle detection.  So now my big hurdle is #1 from the list above. It’s been a bit of a mental shift to go from making something in my garage to sitting in front of a laptop experimenting with different ideas to minimize the interference that these two robots cause each other.  Sometimes it turns into a Sumo Match.

IMG 2295
IMG 2294

 

Tom

 


To err is human.
To really foul up, use a computer.


   
Lee G and robotBuilder reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 7 years ago
Posts: 2508
 

@thrandell 

Apparently I can only react not like anymore 🙂

Your latest look great.  Are you going to share any details of their electronics and software?

Have you seen the reddit Robotics site?  It’s pretty cool.   https://www.reddit.com/r/robotics/

Thanks for the link.  Very interesting to read.

 

 



   
ReplyQuote
Will
 Will
(@will)
Member
Joined: 5 years ago
Posts: 2608
 

Posted by: @robotbuilder

Apparently I can only react not like anymore 🙂

Use the little thumbs up icon on the lower left side, it expands into thumbs up and down which allow you to indicate like or dislike.

 


Anything seems possible when you don't know what you're talking about.


   
THRandell reacted
ReplyQuote
THRandell
(@thrandell)
Brain Donor
Joined: 5 years ago
Posts: 311
Topic starter  

Robot Kin Recognition                                                                                                                                                           

After building two small robots the first thing I needed to do was find a way for them to distinguish their own IR signals from those of the other robot.   After way too many experiments I settled on each robot emitting a message of 8 on/off pulses representing their  unique robot ID.  The idea is that when a robot receives its ID it must be a reflection from some obstacle, whereas if it receives some other ID then it must be from a neighbor robot.  To do that with the Raspberry Pi Pico I used its hardware PWM wrap interrupt.

encode

In my view of the future I see these robots passing multi-byte messages to each other, but at this point I’m just working with the message header.  It contains two start bits, 3 bits for robot ID and another 3 bits for the number of bytes in the message.  For eg. the binary  1 1 0 0 1 0 0 0 represents a message start from robot 1 with zero data bytes.   The message data structure I settled on is an array of 8 one byte integers to hold the header byte + up to 6 data bytes + a CRC check value. 

One of the things I dig about C is the way you can use pointer variables to access data. The pointer variable in this code is used to access the contents of the message array one bit at a time.  The next section on transmit shows you why.

// some declarations
uint8_t message[8];  
uint8_t msg_len = 0; 
uint64_t *ip;        


void encodeHeader(uint8_t messageByte) {
  uint8_t header = 200;  // 11001000 

  if (messageByte == 0) {
    // Add the header to the message[]
    message[7] = header;
    msg_len = 8;
  }
  return;
}

void dumpMessage() {
  uint8_t digit;
  
  ip = &message; // store address of message in pointer variable
  for (int y = 63; y >= 0; y=y-1) {
    digit = (*ip >> y) & 0b0001;  // access the value using the pointer
    printf("%d", digit);
  }
  printf("\n");  
  return;
}

 

transmit

Using the Pico’s PWM wrap interrupt allows me to take the infrared emitting diode’s (IED) 38kHz carrier frequency and control how many Hz make up a binary digit.  Through experimentation I settled on 25 Hz per digit.  In other words, I power the IED for 25 cycles of the carrier frequency for a ‘1’ digit and turn the power down for 25 cycles for a ‘0’ digit.  I believe that’s a Manchester code.  Clear as mud?

So these code snippets have the declarations, pin configuration and routines to emit one message at a time.  The sensor is controller by enabling then disabling the pin interrupt associated with the IED.  The interesting piece is the on_pwm_wrap interrupt handler.  I use the pointer variable to walk through the message array one bit at a time and use the digit as a multiplier to set the level of the duty cycle with 50% for binary 1 and 0% for binary 0. 

#define NUM_PULSES 25

// some declarations
uint8_t message[8];  
uint64_t *ip;        
uint8_t msg_len = 8;  
static uint8_t  active_emitter = 0; 
static uint8_t  level = 50;   


void on_pwm_wrap() {
    static uint16_t pulseCount = 0;
    static uint8_t current_emitter = 7;
    static uint8_t idx = 63;
    uint8_t digit = 0;
    uint8_t dutyCycle = 0; 

    pwm_clear_irq(pwm_gpio_to_slice_num(active_emitter));  
    if (active_emitter != current_emitter) {
      pwm_set_gpio_level(active_emitter, 0);  
      current_emitter = active_emitter;    
      pulseCount = 0;
      idx = 63;
    }
    if (pulseCount == 0) {
      digit = (*ip >> idx) & 0b0001;
      dutyCycle = digit * level;
      pwm_set_gpio_level(active_emitter, pwm_hw->slice[pwm_gpio_to_slice_num(active_emitter)].top * dutyCycle / 100);
      pulseCount++;
    }
    else if (pulseCount == NUM_PULSES) {
      pulseCount = 0;
      idx -= 1;
      if (idx < (64 - msg_len)) {
        idx = 63;
        pwm_set_irq_enabled(pwm_gpio_to_slice_num(active_emitter), false);
        pwm_set_gpio_level(active_emitter, 0);
      }
    }
    else  pulseCount++;
}


void emitMessage(uint8_t sensorOut, uint8_t, sensorIn, uint64_t period) {

  gpio_set_irq_enabled(sensorIn, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);

  uint activeSlice = pwm_gpio_to_slice_num(sensorOut);
  msg_len = (((message[7] & 0b0111) + 1) * 8);  
  active_emitter = sensorOut;
  pwm_clear_irq(activeSlice);
  pwm_set_irq_enabled(activeSlice, true);
  uint64_t timer = time_us_64() + period;
  while (time_us_64() < timer) { }   // let on_pwm_wrap do its thing
  // the set irq disable for the activeSlice is done by on_pwm_wrap

  gpio_set_irq_enabled(sensorIn, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
  return;
}


int main() {

    pwm_clear_irq(slice_S01);  
    pwm_set_irq_enabled(slice_S01, true);  
    irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pwm_wrap);
    irq_set_enabled(PWM_IRQ_WRAP, true);  

    active_emitter = S0_PWM;  
    ip = &message;          


    emitMessage(S0_PWM,S0_INP,countDown);

  return 0;
}

 

Next up receive and decode.

Tom

 

 


To err is human.
To really foul up, use a computer.


   
Lee G reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 7 years ago
Posts: 2508
 

@thrandell 

To do that with the Raspberry Pi Pico I used its hardware PWM wrap interrupt.

Would that make it unusable with other hardware without this PWM wrap interrupt?

Unfortunately I only have one RPi Pico so I wouldn't be able to duplicate the project.

When a robot pulses its address off an obstacle how would another robot detecting the return pulses know it wasn't meant as a signal to communicate? If pulses are pouring in from obstacles and directly from other robots how are they all sorted out as going together or not?

 



   
ReplyQuote
THRandell
(@thrandell)
Brain Donor
Joined: 5 years ago
Posts: 311
Topic starter  

receive                                                                                                                                                

To receive the message being controlled by the PWM wrap interrupt I used another interrupt.  This interrupt is enabled just before the PWM signal begins and it measures the time the receiver pin changes from low to high and from high to low.  This callback routine writes these on/off times to a two dimensional array.  So far I’m transmitting and receiving with one sensor at a time so all four sensors use the same array to hold their timings.  When the PWM wrap interrupt finishes its transmission, both the IED and the receiver pins are interrupt disabled and it starts all over with the next sensor.

#define S0_PWM     8
#define S1_PWM     9
#define S0_INP     6
#define S1_INP     7
#define NUM_PULSES 25      
// 20 pulses was not being received consistently, datasheet states 60

// used by receiver
float   cycleTime = 1/38000.0f * 1000000.0f;// the time in us for 1 cycle at 38kHz
static uint16_t pulses[100][2];   // pair is time of high[0]; and low[1] signals
static uint8_t  currentPulse = 0; // index for pulses we're storing


void rec_callback(uint gpio, uint32_t events) { 
  static uint64_t highTimeStart = 0;
  static uint64_t lowTimeStart = 0;

  if (gpio == S0_INP) {
    if (events == 0b1000) {   // edge rise  __--   This indicates there is no signal
        highTimeStart = time_us_64();
        pulses[currentPulse][1] = highTimeStart - lowTimeStart;
        currentPulse++;
    }
    if (events == 0b0100) {  // edge fall   --__   This indicates there is a signal
      lowTimeStart = time_us_64();
      pulses[currentPulse][0] = lowTimeStart - highTimeStart;
    }
  }
  if (gpio == S1_INP) {
    if (events == 0b1000) { 
        highTimeStart = time_us_64();
        pulses[currentPulse][1] = highTimeStart - lowTimeStart;
        currentPulse++;
    }
    if (events == 0b0100) {
      lowTimeStart = time_us_64();
      pulses[currentPulse][0] = lowTimeStart - highTimeStart;
    }
  }
}

void main (
    gpio_init(S0_INP);     // enable I/O set to GPIO_FUNC_SIO and set to input
    gpio_set_dir(S0_INP, GPIO_IN);
    gpio_pull_up(S0_INP);  // the IR receiver pulls it down when there is a signal
    gpio_init(S1_INP);
    gpio_set_dir(S1_INP, GPIO_IN);
    gpio_pull_up(S1_INP);

    // There can be only one callback routine per processor.  So for multiple input pins just dup this command.
    gpio_set_irq_enabled_with_callback(S0_INP, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, &rec_callback);
    gpio_set_irq_enabled_with_callback(S1_INP, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, false, &rec_callback);



  return;
}

 

decode

The decode process can get a bit complicated so I’ll just give an example of my current approach.  Assume that a three byte message, decimal 202 107 160 (binary 1 1 0 0 1 0 1 0   0 1 1 0 1 0 1 1   1 0 1 0 0 0 0 0) was received and stored in the pulses[100][2] array.  (I’ve added four columns as part of the explanation):

Screen Shot 2022 12 10 at 8.08.13 AM

 

We know that 25 pulses of the carrier frequency take approximately 657.5us so I divide each time by that value and round that result to come up with the number of binary 1s and 0s.  It may look a little weird at first because I remove those leading 0’s and fill in the end of the message with 0’s (if needed).

These values are then used to create an unsigned char array of 1’s and 0’s the length of the message. Using C commands like strncpy( ) the individual bytes are pulled out as strings and transformed into integers.  The CRC check value is the last byte in every message and it is compared to the output of another run of the CRC routine and the message is either accepted or rejected.  Whew.

Tom

 


To err is human.
To really foul up, use a computer.


   
ReplyQuote
THRandell
(@thrandell)
Brain Donor
Joined: 5 years ago
Posts: 311
Topic starter  

Posted by: @robotbuilder

If pulses are pouring in from obstacles and directly from other robots how are they all sorted out as going together or not?

Yep, message collisions are inevitable.  Although handling collisions is further down my to-do list, I was thinking of a few approaches: 

  • robots do not transmit while they are receiving messages;
  • each robot will send bursts of neighbor messages at periodic intervals (tunable);
  • reduce the number of neighbors that a robot can contact by reducing the transmit power (tunable);
  • use something like the Aloha protocol to manage re-transmissions (needs research);
  • recognize that messaging bandwidth is my biggest design constraint so I may need to slow down the robots or speed up the cooperative scheduler loop.

Tom


To err is human.
To really foul up, use a computer.


   
Kids Taxi reacted
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 7 years ago
Posts: 2508
 

I imagined one solution might be a stationary controller that interrogates each bot in turn maybe with WIFI and then resends to all the other bots. I think I read that the RPi pico lacks Wi-Fi?

I am unable to follow your code examples as the Pico hardware is all very complicated.

 



   
ReplyQuote
robotBuilder
(@robotbuilder)
Member
Joined: 7 years ago
Posts: 2508
 

@thrandell 

Aloha protocol

So here I imagine each bot has an accurate clock that is synchronized with the clocks in the other bots. Each bot can only send a message at a particular time during which the other robots are in receive mode.

 



   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 6 years ago
Posts: 8047
 

@robotbuilder The PICOW has WiFi now.


First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
Ron
 Ron
(@zander)
Father of a miniature Wookie
Joined: 6 years ago
Posts: 8047
 

@thrandell You might be able to learn something about collision avoidance from the internet protocol. Sorry it's been decades since I learned all that and having never used any of the low level knowledge it is very foggy but I do remember it because IBM had a protocol that avoided it and I thought was better.


First computer 1959. Retired from my own computer company 2004.
Hardware - Expert in 1401, 360, fairly knowledge in PC plus numerous MPU's & MCU's
Major Languages - Machine language, 360 Macro Assembler, Intel Assembler, PL/I and PL1, Pascal, Basic, C plus numerous job control and scripting languages.
My personal scorecard is now 1 PC hardware fix (circa 1982), 1 open source fix (at age 82), and 2 zero day bugs in a major OS.


   
ReplyQuote
Page 4 / 6