Author Topic: help... basic 2d mapping using Sharp sensors  (Read 5403 times)

0 Members and 1 Guest are viewing this topic.

Offline toastmanTopic starter

  • Jr. Member
  • **
  • Posts: 12
  • Helpful? 0
help... basic 2d mapping using Sharp sensors
« on: March 26, 2007, 08:10:30 PM »
Hi... I've read the tutorial on the main website about using sharp IR distance sensors for basic 2d mapping. I wanted to know in more details on how to do the basic 2d mapping by using PIC. I'm planning to use 2 sensors and 1 servo motor. I plan to do it using PIC16F876A with oscillator 20 MHz and program it in C. Can anyone guide me on how to do the programming?

I know that we need PWM signals to drive the servo and that PIC has PWM signal generator. But I can't use it unless I reduce the frequency of my oscillator. If I want to keep using the 20MHz oscillator, can anyone teach me how to generate the PWM?

For the sensor readings, I tried using arrays to store the values. The codes below are the codes I used to test whether I've managed to know what is inside the arrays. I use the datalogging and hyperterminal as I've read in the main website to see the values. But I ended up getting nothing in the hyperterminal screen. Did I do anything wrong in my codes?


#include <16f876a.h>
#device adc=8
#use delay(clock=20000000)
#fuses hs,noprotect,nowdt,nolvp
//setup uart for serial communication with PC
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,PARITY=N)

#byte PORTA=5
#byte PORTB=6
#byte PORTC=7

main()
{
  int i,value[10];
  set_tris_b(0);
  set_tris_c(0x80);     //set all port c as output except C7

  //setup port a as analog inputs
  setup_port_a(ALL_ANALOG);
  //use PIC clock as ADC clock
  setup_adc(ADC_CLOCK_INTERNAL);

  //test if pic is working or not
  portb=0x7f;             //Turn on RB7 (PIC status LED)
  delay_ms(1000);
  portb = 0xff;           //turn off all led

  //read from channel 0 (RA0)
  set_adc_channel(0);
  do
  {
      for(i = 0; i < 10; i++)
      {
         portb = 0xff;              //turn off all led
         value = read_adc();  //read the output voltage
         printf("%u,",value);
         delay_ms(5000);         //delay for 5 sec
         portb = 0x7f;             //turn on led, ready for next value
         delay_ms(5000);         //delay for 5 sec
      }
  }while(1);
}

Offline Admin

  • Administrator
  • Supreme Robot
  • *****
  • Posts: 11,703
  • Helpful? 173
    • Society of Robots
Re: help... basic 2d mapping using Sharp sensors
« Reply #1 on: March 28, 2007, 04:35:40 AM »
Quote
I know that we need PWM signals to drive the servo and that PIC has PWM signal generator. But I can't use it unless I reduce the frequency of my oscillator. If I want to keep using the 20MHz oscillator, can anyone teach me how to generate the PWM?
Assuming that you are doing to port calls properly (the status led test in your code works, right?), the easiest way to figure out your PWM is to hook up the output to an oscilloscope and measure the exact PWM. Then just tweak the delay_ms(whatever) until you get a wavelength of about 1.4ms.

Quote
For the sensor readings, I tried using arrays to store the values. The codes below are the codes I used to test whether I've managed to know what is inside the arrays. I use the datalogging and hyperterminal as I've read in the main website to see the values. But I ended up getting nothing in the hyperterminal screen. Did I do anything wrong in my codes?
The problem is that you are trying to output 'value' instead of 'value'. The rest looks correct. If you just outputted pure text ('hello world!'), does it work?

Offline snow

  • Full Member
  • ***
  • Posts: 73
  • Helpful? 0
Re: help... basic 2d mapping using Sharp sensors
« Reply #2 on: March 28, 2007, 05:37:12 AM »
You can generate PWM signal with something like this:

Code: [Select]
while(1)
{
portb = 0xff;
delay_us(1500);
portb = 0x00;
delay_us(18500);
}

This will make PWM signal on all portb pins, with period of 20ms and duty cycle time of 1.5ms. 1.5ms means neutal position for servo. Period doesnt have to be exactly 20ms, so instead of waiting using delay function you can do something useful during that time. But it has to be somewhere around 20ms.

Another option that you might try generating PWM signal using CCP output compare module, like here: http://forum.microchip.com/fb.aspx?m=195626. I suggest you read the whole topic there.

Third option would be to have some external PWM module or another PIC - small one with internal RC oscilator and you comunicate with it via SPI and he takes care of all PWM generating.

I guess it really depends on how much free time does your MCU have...

Offline Admin

  • Administrator
  • Supreme Robot
  • *****
  • Posts: 11,703
  • Helpful? 173
    • Society of Robots
Re: help... basic 2d mapping using Sharp sensors
« Reply #3 on: March 28, 2007, 05:50:55 AM »
Quote
Period doesnt have to be exactly 20ms, so instead of waiting using delay function you can do something useful during that time. But it has to be somewhere around 20ms.
I agree with Snow. I found that if I PWM less than ~20ms my futaba servos start to overheat . . .

Offline toastmanTopic starter

  • Jr. Member
  • **
  • Posts: 12
  • Helpful? 0
Re: help... basic 2d mapping using Sharp sensors
« Reply #4 on: May 14, 2007, 12:12:05 AM »
I've changed my mind on doing basic 2d mapping. Now I'm just trying to scan environment, stop horizontal movement once the sensor detect something at certain range, move another servo up and down (this is for later implementation), then start scanning again. I've made program to test sensor reading and output them to hypertherminal and also create program to control servo by just output high and low pins as posted by snow. Now I want to combine them, but the motor control signals get really bad and servo moves crazily (I attached my program codes).

I'm thinking of going for the third option, implementing the servo control on different pic. I'm not sure on how to communicate between the two PIC. And I still need the main PIC to receive some feedback from PC. Help plz...

Code: [Select]
//Thesis: Construction of a Closed-loop Vision System
//Sensor Scanning System ver.1
//
//Description:
//- move servoH from -80 to +80 degree
//- scan environment at each degree
//- if the sensor detects object:
//    --> for SensorDown @ distance less than 110 cm
//    --> for SensorUp @ distance less than 80 cm
//   --> stop the movement and start moving servoV up n down
//


/****************** PIC Setup ******************/

#include <16f876a.h>
#device adc=8                       //8-bit ADC
#use delay(clock=20000000)
#fuses hs,noprotect,nowdt,nolvp
//setup uart for serial communication with PC
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,PARITY=N)

#byte PORTA=5
#byte PORTB=6
#byte PORTC=7

#define servoH          PIN_C4
#define servoV          PIN_C3
#define STATUS_LED      PIN_B7
#define WARNING_LED     PIN_B6
#define SWITCH1         PIN_B0
#define SensorDown         0        //Red sensor
#define SensorUp           1        //Black sensor
#define Num_Measurements   5

/***** Variable and function declarations *****/

int i, count, stop;
long value, UpValue, DownValue;
long total[2] = {0};

void init_ports();
void init_adc(int channel);
void read();
void scan();
void check();
void init_values();
void MoveServoH();
void MoveServoV();

/*************** Main Function ***************/

void main()
{
  //initialize ports
  init_ports();

  portb=0xff;              //test if pic is working or not
  output_low(STATUS_LED);  //turn on status led (B7)

  MoveServoH();            //start moving horizontally
}//end main


/************ Additional Functions ************/

//initialize ports
void init_ports()
{
   set_tris_b(0x01);       //all port b as output except b0
   set_tris_c(0x80);       //all port c as output except c7

   //setup port A as analog inputs, Vdd as reference
   //0-5V --> 0-255
   setup_port_a(ALL_ANALOG);
}//end init_ports

//initialize adc channel
void init_adc(int channel)
{
   //use PIC clock as ADC clock
   setup_adc(ADC_CLOCK_INTERNAL);
   //set adc channel
   set_adc_channel(channel);
   delay_us(50);
}//end init_adc

//read from current adc channel
void read()
{
   value = read_adc();
   setup_adc(ADC_OFF);
}//end read

//scan environment
void scan()
{
      //Every around 60 ms
      if(count%3 == 0 && i < Num_Measurements)
      {
         //Get SensorDown data
         init_adc(SensorDown);
         //Get measurement
         read();
         total[SensorDown] = total[SensorDown] + value;

         //Get SensorUp data
         init_adc(SensorUp);
         read();
         total[SensorUp] = total[SensorUp] + value;
         i++;
      }
}//end scan

//check the adc value
void check()
{
   //if SensorDown detected object at distance less than 110 cm (26)
   //or SensorUp detected object at distance less than 80 cm (39)
   if(DownValue > 26 || UpValue > 39)
   {
      output_low(WARNING_LED);      //light up warning led
      stop = 1;                     //stop the current movement
   }
}//end check

//reinitialize some values
void init_values()
{
   i = 0; count = 0; stop = 0;
   total[SensorDown] = 0;
   total[SensorUp] = 0;
   delay_ms(500);
   output_high(WARNING_LED);
}


//Move servoH from -80 to +80 degree
//initial position is 0 degree then move to +80 then -80
void MoveServoH()
{
  while(1)
  {
   init_values();       //initialize all values
   //Set motor to 0 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(600);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18500);     //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 20 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(800);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18300);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 40 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(1000);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18100);                 //delay such that overall period of PWM is around 20 ms
      count++;


      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 60 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(1200);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(17900);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 80 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(1400);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(17700);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 60 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(1200);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(17900);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 40 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(1000);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18100);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 20 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(800);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18300);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to 0 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(600);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18500);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }
     
      if(stop == 1)
      {
         moveServoV();
         break;
      }
   }

   init_values();       //initialize all values
   //Set motor to -20 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(400);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18700);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to -40 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(200);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18900);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }
    }

   init_values();       //initialize all values
   //Set motor to -60 degree for about 3 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoH);
      //Set horizontal servo control to low
      output_low(servoV);
      delay_us(19100);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }

   }

   init_values();       //initialize all values
   //Set motor to -80 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(700);
      //Set vertical servo control to low
      output_low(servoH);
      delay_us(200);
      //Set horizontal servo control to low
      output_low(servoV);
      delay_us(19100);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }

    }

   init_values();       //initialize all values
   //Set motor to -60 degree for about 3 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(19100);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }

    }

   init_values();       //initialize all values
   //Set motor to -40 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(200);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18900);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }

    }

   init_values();       //initialize all values
   //Set motor to -20 degree for about 2 sec
   while (count != 100)
   {
      //Set horizontal servo control to high
      output_high(servoH);
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(400);
      //Set horizontal servo control to low
      output_low(servoH);
      delay_us(18700);                 //delay such that overall period of PWM is around 20 ms
      count++;

      scan();              //scan environment

      //after 5 consecutive measurements (when around 300 ms has passed)
      if(i == Num_Measurements)
      {
         //Get average values of each sensor
         DownValue = total[SensorDown]/Num_Measurements;
         UpValue = total[SensorUp]/Num_Measurements;
         check();       //check whether the values exceed the requirement
      }

      if(stop == 1)
      {
         moveServoV();
         break;
      }
   }
 }//end while
}

void MoveServoV()
{
   //initialize count
   count = 0;
   //Set servoV to -60 degree for about 3 sec
   while (count != 150)
   {
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(700);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(19300);                 //delay such that overall period of PWM is around 20 ms
      count++;
    }

   count = 0;
   //Set servoV to -45 degree for about 3 sec
   while (count != 150)
   {
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(19100);                 //delay such that overall period of PWM is around 20 ms
      count++;
    }

   count = 0;
   //Set motor to -30 degree for about 3 sec
   while (count != 150)
   {
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(1100);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(18900);                 //delay such that overall period of PWM is around 20 ms
      count++;
    }

   init_values();       //initialize all values
   //Set servoV to -45 degree for about 3 sec
   while (count != 150)
   {
      //Set vertical servo control to high
      output_high(servoV);
      delay_us(900);
      //Set vertical servo control to low
      output_low(servoV);
      delay_us(19100);                 //delay such that overall period of PWM is around 20 ms
      count++;
   }
}

edited..... sorry ^^
« Last Edit: May 14, 2007, 05:52:57 AM by toastman »

Offline Admin

  • Administrator
  • Supreme Robot
  • *****
  • Posts: 11,703
  • Helpful? 173
    • Society of Robots
Re: help... basic 2d mapping using Sharp sensors
« Reply #5 on: May 14, 2007, 05:00:51 AM »
when posting big chunks of code, use the bracket-code-bracket feature on the forum.

its the picture of the # when in a reply message window.

most people dont know about it, but it just gets messy otherwise :P

 


Get Your Ad Here

data_list