主頁 >  其他 > ROS機器人小車底盤DIY有何難?不枉做一個程式猿,軀殼碼上有功能

ROS機器人小車底盤DIY有何難?不枉做一個程式猿,軀殼碼上有功能

2021-04-05 11:16:12 其他

ROS機器人小車底盤DIY有何難?不枉做一個程式猿,軀殼碼上有功能

前文的軀殼

驅動板
arduino stm32F103c8t6系統板的編程任務:
驅動TB6612
驅動GY85
驅動ps2遙控接收器
編碼器的檢測
PID速位控制
運動學演算法
rosserial通訊協議


arduino好處是庫比較多,上手快捷,
可以找一些開源的資料,按需整合,移植,除錯,
但是有些還會遇到困難,需要自己創作,

問題:

比如編碼器的庫,可能找了很多都不太合適,需要改成中斷的方案,
stm32使用arduino encoder庫的改造草案https://blog.csdn.net/qq_38288618/article/details/106839319
比如rosserial的通訊協議探索,

ROS中rosserial通訊協議初探https://blog.csdn.net/qq_38288618/article/details/102931684
需要用ros配合來生成arduino用的庫遇到問題,
ROS與Arduino硬體之rosserial_arduino(win10)https://blog.csdn.net/qq_38288618/article/details/104082877

等等吧,相信花點時間都能攻克,


上主檔案的碼:

#define USE_STM32_HW_SERIAL
#include <wirish_debug.h>
//#include <ros.h>
#include "zr_ros.h"
//header file for publishing velocities for odom
#include <zr_movebase_msgs/Velocities.h>

//header file for cmd_subscribing to "cmd_vel"
#include <geometry_msgs/Twist.h>

//header file for pid server
#include <zr_movebase_msgs/PID.h>

//header files for imu
#include <ros_arduino_msgs/RawImu.h>
#include <geometry_msgs/Vector3.h>
#include <ros/time.h>

//#include <zr_protocol/hw_info.h>
#include <zr_protocol/hw_cmd_.h>
#include "zr_info.h"

#include "config.h"
#include "Motor.h"
#include "PID.h"
#include "Kinematics.h"

#include <Wire.h>
#include "imu_configuration.h"

#include <PS2X_lib.h>  //for v1.6
#include "PS2X_zzz.h"

PS2X_ZZZ PS2X_ez(_PS2_CLK, _PS2_CMD, _PS2_SEL, _PS2_DAT, true, true);

//Kinematics kinematics(MAX_RPM, WHEEL_DIAMETER, BASE_WIDTH, PWM_BITS);
Kinematics kinematics(Kinematics::ZR_BASE, MAX_RPM, WHEEL_DIAMETER, FR_WHEELS_DISTANCE, LR_WHEELS_DISTANCE, PWM_BITS);
//Motor motor1(MOTOR1_PWM, MOTOR1_IN_A, MOTOR1_IN_B); //front
Motor motor1(MOTOR1_PWM, MOTOR1_IN_A, MOTOR1_IN_B); //front
Motor motor2(MOTOR2_PWM, MOTOR2_IN_A, MOTOR2_IN_B); //front
Motor motor3(MOTOR3_PWM, MOTOR3_IN_A, MOTOR3_IN_B); //back
Motor motor4(MOTOR4_PWM, MOTOR4_IN_A, MOTOR4_IN_B); //back
//COUNTS_PER_REV = 0 if no encoder
int Motor::counts_per_rev_ = COUNTS_PER_REV;
PID motor1_pid(-255, 255, K_P, K_I, K_D);
PID motor2_pid(-255, 255, K_P, K_I, K_D);
PID motor3_pid(-255, 255, K_P, K_I, K_D);
PID motor4_pid(-255, 255, K_P, K_I, K_D);

//zzz ros ----------------------------------------------------------------
double g_req_angular_vel_z = 0;
double g_req_linear_vel_x = 0;
double g_req_linear_vel_y = 0;
unsigned char led_blink=0;
unsigned char ros_msg_ctrl=1;
unsigned char stick_wait_ok=0;
unsigned char stick_setup_ok=1;
unsigned long g_prev_loop_first_time = 0;
unsigned long g_prev_stick_ctrl_time = 0;
unsigned long g_prev_stick_time = 0;
unsigned long g_prev_imu_check_time = 0;
unsigned long g_prev_led_blink_time = 0;
unsigned long g_prev_command_time = 0;
unsigned long g_prev_control_time = 0;
unsigned long g_publish_vel_time = 0;
unsigned long g_prev_imu_time = 0;
unsigned long g_prev_debug_time = 0;
void init_g_prev_time(unsigned long t);


bool g_is_first = true;

char g_buffer[50];

//callback function prototypes
void commandCallback(const geometry_msgs::Twist& cmd_msg);
void PIDCallback(const zr_movebase_msgs::PID& pid);
ros::NodeHandle nh;
ros::Subscriber<geometry_msgs::Twist> cmd_sub("cmd_vel", commandCallback);
ros::Subscriber<zr_movebase_msgs::PID> pid_sub("pid", PIDCallback);

ros_arduino_msgs::RawImu raw_imu_msg;
ros::Publisher raw_imu_pub("raw_imu", &raw_imu_msg);
zr_movebase_msgs::Velocities raw_vel_msg;
ros::Publisher raw_vel_pub("raw_vel", &raw_vel_msg);

//zzz ros-------------------------------------------------------------------

#define IO_REG_TYPE      uint32_t
#define PIN_TO_BASEREG(pin)             (portInputRegister(digitalPinToPort(pin)))
#define PIN_TO_BITMASK(pin)             (digitalPinToBitMask(pin))
#define DIRECT_PIN_READ(base, mask)     (((*(base)) & (mask)) ? 1 : 0)

typedef struct {
  volatile IO_REG_TYPE * pin1_register;
  volatile IO_REG_TYPE * pin2_register;
  IO_REG_TYPE            pin1_bitmask;
  IO_REG_TYPE            pin2_bitmask;
  uint8_t pin1;
  uint8_t pin2;
  uint8_t state;
  int32_t position;
} Encoder_internal_state_t;

Encoder_internal_state_t * interruptArgs[4];
Encoder_internal_state_t encoder1;
Encoder_internal_state_t encoder2;
Encoder_internal_state_t encoder3;
Encoder_internal_state_t encoder4;
uint8_t oldstate=0;
float stick_a=0.0;
float stick_v=0.0;
float stick_vy=0.0;
void stick_callback(PS2X_ZZZ::PSS stick_dat){
  //
  if(stick_wait_ok){
  int d=stick_dat.lx-128;
  int d_abs;
  int d_f;
  d_f=d<0?-1:1;
  d_abs=abs(d);
  d=d_abs<2?0:d;
  d_f=d==0?0:d_f;
  stick_a=((float)d-2.0*d_f)/126.0;
  
  d=stick_dat.ry-128;
  d_f=d<0?-1:1;
  d_abs=abs(d);
  d=d_abs<2?0:d;
  d_f=d==0?0:d_f;
  stick_v=-((float)d-2.0*d_f)/126.0;//add"-" zzz 6612 is not same as 8833
//!!!!MECANUM  add y director//
  d=stick_dat.rx-128;
  d_f=d<0?-1:1;
  d_abs=abs(d);
  d=d_abs<2?0:d;
  d_f=d==0?0:d_f;
  stick_vy=((float)d-2.0*d_f)/126.0;
  //Serial.println(stick_dat.lx,DEC);

  ros_msg_ctrl=0;
  //stick yaokong youxian 
  g_req_linear_vel_x=stick_v*0.4;//0.1;//0.4mps
  g_req_linear_vel_y=stick_vy*0.4;//0.1;//0.4mps
  g_req_angular_vel_z=stick_a*3.14/2;//45du/s
  g_prev_stick_ctrl_time=millis();
  g_prev_command_time =millis();
  }
}
void update1(Encoder_internal_state_t *arg) {
      //uint8_t state = arg->state & 3;
      //if (digitalRead(arg->pin1)) state |= 4;
      //if (digitalRead(arg->pin2)) state |= 8;

      uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask);
      uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask);
      uint8_t state = arg->state & 3;
      if (p1val) state |= 4;
      if (p2val) state |= 8;
      
      arg->state = (state >> 2);
   
      switch (state) {
        case 1: case 7: case 8: case 14:
          arg->position++;
          return;
        case 2: case 4: case 11: case 13:
          arg->position--;
          return;
        case 3: case 12:
          arg->position += 2;
          return;
        case 6: case 9:
          arg->position -= 2;
          return;
      }
}
void update(void) {
  //noInterrupts();
  update1(interruptArgs[0]);
  update1(interruptArgs[1]);
  update1(interruptArgs[2]);
  update1(interruptArgs[3]);
  //interrupts();
}
//void callback_srv(const zr_protocol::hw_info::Request & req, zr_protocol::hw_info::Response & res){
//  res.output=RosDeviceInfo::getInfoValue(req.input);  
//}
//ros::ServiceServer<zr_protocol::hw_info::Request, zr_protocol::hw_info::Response> server("zr_hw_info",&callback_srv);

void callback_hw_cmd(const zr_protocol::hw_cmd::Request & req, zr_protocol::hw_cmd::Response & res) {
  if (strcmp(req.cmd, "chr") == 0) {    
    uint8_t dat[8] ;
    char i=1;
    char maxi=req.input_length>9?9:req.input_length;
    while( i<req.input_length){dat[i-1]=req.input[i];i++;}
    i--;
    while( i<8){dat[i]=0;i++;}
    
    //lcd.createChar(req.input[0], dat);
    res.output = ( unsigned char*) "ok";
    res.output_length=2;    
  } else {
    res.output = ( unsigned char*) RosDeviceInfo::getInfoValue(req.cmd);    
    res.output_length=zr::buffStrLen((char*) res.output);
  }
}
ros::ServiceServer<zr_protocol::hw_cmd::Request, zr_protocol::hw_cmd::Response> server_hw_cmd("zr_hw_cmd", &callback_hw_cmd);

void ROS_setup()
{  
  nh.initNode();
  ArduinoHardware* hw = nh.getHardware();
  hw->setBaud(500000);
  hw->init();
  //Serial.begin(500000);
  nh.advertiseService(server_hw_cmd);
  nh.advertise(raw_imu_pub);
  nh.advertise(raw_vel_pub);
  nh.subscribe(pid_sub);
  nh.subscribe(cmd_sub);
}
void init_encoder_pin_data(uint8_t pin1,uint8_t pin2,Encoder_internal_state_t *encoder,uint8_t idx){
  encoder->pin1 = pin1;
  encoder->pin2 = pin2;
  encoder->pin1_register = PIN_TO_BASEREG(pin1);
  encoder->pin1_bitmask = PIN_TO_BITMASK(pin1);
  encoder->pin2_register = PIN_TO_BASEREG(pin2);
  encoder->pin2_bitmask = PIN_TO_BITMASK(pin2);
  //encoder->state=0;
  encoder->position=0;
  pinMode(pin1, INPUT);  
  //digitalWrite(pin1, HIGH);
  //pinMode(pin1, INPUT_PULLUP);
  digitalWrite(pin1, LOW);
  pinMode(pin1, INPUT_PULLDOWN);
  
  pinMode(pin2, INPUT);
  //digitalWrite(pin2, HIGH);
  //pinMode(pin2, INPUT_PULLUP);
  digitalWrite(pin2, LOW);  
  pinMode(pin2, INPUT_PULLDOWN);
  interruptArgs[idx]=encoder;
  //
  delayMicroseconds(2000);
  uint8_t s = 0;
  if (DIRECT_PIN_READ(encoder->pin1_register, encoder->pin1_bitmask)) s |= 1;
  if (DIRECT_PIN_READ(encoder->pin2_register, encoder->pin2_bitmask)) s |= 2;
  encoder->state = s;
}

Kinematics::outputf req_rpm;
int spd1,spd2,spd3,spd4;
float set1,set2,set3,set4;
float cur1,cur2,cur3,cur4;
float pid_p,pid_i,pid_d;
void moveBase()
{  
  //get the required rpm for each motor based on required velocities
  req_rpm = kinematics.getRPM(g_req_linear_vel_x, g_req_linear_vel_y, g_req_angular_vel_z);

  //the required rpm is capped at -/+ MAX_RPM to prevent the PID from having too much error
  //the PWM value sent to the motor driver is the calculated PID based on required RPM vs measured RPM
  
  set1=req_rpm.motor1;//(float) constrain(req_rpm.motor1, -MAX_RPM, MAX_RPM);
  cur1=motor1.rpm;
  spd1=motor1_pid.compute(set1, cur1);
  motor1.spin(spd1);
  
  set3=req_rpm.motor3;//(float) constrain(req_rpm.motor3, -MAX_RPM, MAX_RPM);
  cur3=motor3.rpm;
  spd3=motor3_pid.compute(set3, cur3);
  motor3.spin(spd3);
  
  set2=-req_rpm.motor2;//(float) constrain(-req_rpm.motor2, -MAX_RPM, MAX_RPM);
  cur2=motor2.rpm;
  spd2=motor2_pid.compute(set2, cur2);  
  motor2.spin(spd2);
  
  set4=-req_rpm.motor4;//(float) constrain(-req_rpm.motor4, -MAX_RPM, MAX_RPM);
  cur4=motor4.rpm;
  spd4=motor4_pid.compute(set4, cur4); 
  motor4.spin(spd4);
}
void stopBase()
{
  g_req_linear_vel_x = 0.0;
  g_req_linear_vel_y = 0.0;
  g_req_angular_vel_z = 0.0;
}

void publishVelocities()
{
  //update the current speed of each motor based on encoder's count
//  motor1.updateSpeed(encoder1.position);
//  motor2.updateSpeed(encoder2.position);
//  motor3.updateSpeed(encoder3.position);
//  motor4.updateSpeed(encoder4.position);

  Kinematics::velocities vel;
  vel = kinematics.getVelocities(motor1.rpm, -motor2.rpm, motor3.rpm, -motor4.rpm);

  //fill in the object
  raw_vel_msg.linear_x = vel.linear_x;
  raw_vel_msg.linear_y = vel.linear_y;
  raw_vel_msg.angular_z = vel.angular_z;

//
//Serial.println("encoder  :");
//Serial.print(encoder1.position);Serial.print(" , ");
//Serial.print(encoder2.position);Serial.print(" , ");
//Serial.print(encoder3.position);Serial.print(" , ");
//Serial.println(encoder4.position);
//Serial.println("publishVelocities");
//Serial.print("linear_x  :");Serial.println(vel.linear_x);
//Serial.print("linear_y  :0");
//Serial.print("angular_z :");Serial.println(vel.angular_z);
  //publish raw_vel_msg object to ROS
  raw_vel_pub.publish(&raw_vel_msg);
}

void checkIMU_zzz()
{
  //this function checks if IMU is present
  Serial.println("Accelerometer");
  raw_imu_msg.accelerometer = checkAccelerometer();
raw_imu_msg.accelerometer = checkAccelerometer();
raw_imu_msg.accelerometer = checkAccelerometer();
  Serial.println("gyroscope");  
  raw_imu_msg.gyroscope = checkGyroscope();

  
  
  Serial.println("magnetometer");
  raw_imu_msg.magnetometer = checkMagnetometer();

Serial.println(raw_imu_msg.accelerometer);
Serial.println(raw_imu_msg.gyroscope);
Serial.println(raw_imu_msg.magnetometer);
  if (!raw_imu_msg.accelerometer)
  {
    Serial.println("Accelerometer NOT FOUND!");
  }

  if (!raw_imu_msg.gyroscope)
  {
    Serial.println("Gyroscope NOT FOUND!");
  }

  if (!raw_imu_msg.magnetometer)
  {
    Serial.println("Magnetometer NOT FOUND!");
  }

g_is_first = false;
}
void publishIMU_zzz()
{
  if (raw_imu_msg.accelerometer || raw_imu_msg.gyroscope || raw_imu_msg.magnetometer){
    //this function publishes raw IMU reading
    raw_imu_msg.header.stamp = nh.now();
    raw_imu_msg.header.frame_id = "imu_link";

    //measure accelerometer
    if (raw_imu_msg.accelerometer){
      measureAcceleration();
      raw_imu_msg.raw_linear_acceleration = raw_acceleration;
    }

    //measure gyroscope
    if (raw_imu_msg.gyroscope){
      measureGyroscope();
      raw_imu_msg.raw_angular_velocity = raw_rotation;
    }

    //measure magnetometer
    if (raw_imu_msg.magnetometer){
      measureMagnetometer();
      raw_imu_msg.raw_magnetic_field = raw_magnetic_field;
    }

    //publish raw_imu_msg object to ROS
//    Serial.println("publish raw_imu_msg------");
//    Serial.println("raw_acceleration");
//    Serial.print(raw_acceleration.x);Serial.print(" , ");
//    Serial.print(raw_acceleration.y);Serial.print(" , ");
//    Serial.println(raw_acceleration.z);
//    Serial.println("raw_rotation");
//    Serial.print(raw_rotation.x);Serial.print(" , ");
//    Serial.print(raw_rotation.y);Serial.print(" , ");
//    Serial.println(raw_rotation.z);
//    Serial.println("raw_magnetic_field");
//    Serial.print(raw_magnetic_field.x);Serial.print(" , ");
//    Serial.print(raw_magnetic_field.y);Serial.print(" , ");
//    Serial.println(raw_magnetic_field.z);
    
    raw_imu_pub.publish(&raw_imu_msg);
  }
}
void printDebug()
{
  sprintf (g_buffer, "Encoder FrontLeft: %ld", encoder1.position);
  nh.loginfo(g_buffer);
  sprintf (g_buffer, "Encoder RearLeft: %ld", encoder3.position);
  nh.loginfo(g_buffer);
  sprintf (g_buffer, "Encoder FrontRight: %ld", encoder2.position);
  nh.loginfo(g_buffer);
  sprintf (g_buffer, "Encoder RearRight: %ld", encoder4.position);
  nh.loginfo(g_buffer);
}
void printDebug(float dat1,float dat2,float dat3,float dat4)
{
  sprintf (g_buffer, "dat1: %lf", dat1);
  nh.loginfo(g_buffer);
  sprintf (g_buffer, "dat2: %lf", dat2);
  nh.loginfo(g_buffer);
  sprintf (g_buffer, "dat3: %lf", dat3);
  nh.loginfo(g_buffer);
  sprintf (g_buffer, "dat4: %lf", dat4);
  nh.loginfo(g_buffer);
}
void init_g_prev_time(unsigned long t){
 g_prev_loop_first_time=t;
 g_prev_stick_ctrl_time = t;
 g_prev_stick_time = t;
 g_prev_imu_check_time = t;
 g_prev_led_blink_time = t;
 g_prev_command_time = t;
 g_prev_control_time = t;
 g_publish_vel_time = t;
 g_prev_imu_time = t;
 g_prev_debug_time = t;
}
void setup() {
  motor1.spin(0);
  motor2.spin(0);
  motor3.spin(0);
  motor4.spin(0);
  
  afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY);
  PS2X_ez.PS2_PSS_callback=stick_callback;

  init_encoder_pin_data(MOTOR1_ENCODER_A,MOTOR1_ENCODER_B,&encoder1,0);//front
  init_encoder_pin_data(MOTOR2_ENCODER_A,MOTOR2_ENCODER_B,&encoder2,1);//front
  init_encoder_pin_data(MOTOR3_ENCODER_A,MOTOR3_ENCODER_B,&encoder3,2);//front
  init_encoder_pin_data(MOTOR4_ENCODER_A,MOTOR4_ENCODER_B,&encoder4,3);//front
  Timer4.pause();
  Timer4.setPrescaleFactor(72); // 1 μs resolution
  Timer4.setMode(TIMER_CH3, TIMER_OUTPUTCOMPARE);    
  Timer4.setCount(0);
  Timer4.setOverflow(100);//脈沖5000hz/s,中斷設定10000次/s檢測,保證高低電平各取樣2個點
  Timer4.setCompare(TIMER_CH1, 100);   // somewhere in the middle
  Timer4.attachInterrupt(TIMER_CH1, update);
  Timer4.refresh();
  Timer4.resume();

  //Serial.begin(9600);
  delay(10);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(PC13,HIGH);

  pinMode(PB7, INPUT_PULLDOWN);
  Wire.setClock(400000);
  Wire.begin();

  ROS_setup();
  delay(100);
  checkIMU_zzz();//cost long time.
  init_g_prev_time(millis());
}


int c=0;
long pp=-999;
  int pwm1,pwm2,pwm3,pwm4;
void loop() {

  //delay(5);
  //if(c%100==0){    c=0;  }  c++;
  //this block drives the robot based on defined rate
  if (stick_wait_ok==0){
    if(millis()>g_prev_loop_first_time+1000){
      stick_wait_ok=1;//wait 1s ,kepp no cmd
      stick_setup_ok=PS2X_ez.ps_setup;//wait 1s ,try to conect stick device.
    }
  }
  if(stick_setup_ok){//< 1s value==1,> 1s value == the last PS2X_ez.ps_setup
    if ((millis() - g_prev_stick_time) >= (100)){
      stick_a=0.0;
      stick_v=0.0;
      PS2X_ez.PS2_loop();      
      g_prev_stick_time = millis();
    }
  }//else no stick device or device error.
  if ((millis() - g_prev_stick_ctrl_time) >= (250)){
    ros_msg_ctrl=1;
  }
  if ((millis() - g_prev_command_time) >= (200)){
    stopBase();
  }
  //this block drives the robot based on defined rate
  if ((millis() - g_prev_control_time) >= 20){//(1000 / COMMAND_RATE)
    motor1.updateSpeed(encoder1.position);
    motor2.updateSpeed(encoder2.position);
    motor3.updateSpeed(encoder3.position);
    motor4.updateSpeed(encoder4.position);
    moveBase();
//test:    
//    pwm1=motor1_pid.compute(constrain(20, -MAX_RPM, MAX_RPM), motor1.rpm);
//    motor1.spin(pwm1);
//    pwm2=motor2_pid.compute(constrain(-20, -MAX_RPM, MAX_RPM), motor2.rpm);
//    motor2.spin(pwm2);
//    pwm3=motor3_pid.compute(constrain(20, -MAX_RPM, MAX_RPM), motor3.rpm);
//    motor3.spin(pwm3);
//    pwm4=motor4_pid.compute(constrain(-20, -MAX_RPM, MAX_RPM), motor4.rpm);
//    motor4.spin(pwm4);
    
    g_prev_control_time = millis();
  }
  //this block publishes velocity based on defined rate
  if ((millis() - g_publish_vel_time) >= (1000 / VEL_PUBLISH_RATE)){    
    publishVelocities();

//    Serial.println(String("1posi:")+encoder1.position);
//    Serial.println(String("1rpm:")+motor1.rpm);
//    Serial.println(String("1pwm:")+pwm1);
//    Serial.println(String("2posi:")+encoder2.position);
//    Serial.println(String("2rpm:")+motor2.rpm);
//    Serial.println(String("2pwm:")+pwm2);
    g_publish_vel_time = millis();
  }
  //this block publishes the IMU data based on defined rate
  if ((millis() - g_prev_imu_time) >= (1000 / IMU_PUBLISH_RATE)){
    //sanity check if the IMU exits
    if (g_is_first){
      checkIMU_zzz();
    }else{
      //publish the IMU data
      publishIMU_zzz();
    }
    g_prev_imu_time = millis();
  }
  if ((millis() - g_prev_led_blink_time) >= (500 )){
    if(led_blink==0){
      led_blink=1;
    }else{
      led_blink=0;
    }
    digitalWrite(PC13, led_blink);
    g_prev_led_blink_time = millis();
  } 
  if ((millis() - g_prev_imu_check_time) >= (100 )){    
    //checkIMU_zzz();
    g_prev_imu_check_time = millis();
  }
  


  //this block displays the encoder readings. change DEBUG to 0 if you don't want to display
  if(DEBUG){
    if ((millis() - g_prev_debug_time) >= (1000 / DEBUG_RATE)){
      
      g_prev_debug_time = millis();
    }
  }
  //call all the callbacks waiting to be called
  nh.spinOnce();
}
void PIDCallback(const zr_movebase_msgs::PID& pid)
{
  //callback function every time PID constants are received from lino_pid for tuning
  //this callback receives pid object where P,I, and D constants are stored
  pid_p=pid.p;
  pid_i=pid.i;
  pid_d=pid.d;
  //printDebug((float)pid_p,(float)pid_i,(float)pid_d,(float)0.0);//==0??
  motor1_pid.updateConstants(pid.p, pid.i, pid.d);
  motor2_pid.updateConstants(pid.p, pid.i, pid.d);
  motor3_pid.updateConstants(pid.p, pid.i, pid.d);
  motor4_pid.updateConstants(pid.p, pid.i, pid.d);
}

void commandCallback(const geometry_msgs::Twist& cmd_msg)
{
  //callback function every time linear and angular speed is received from 'cmd_vel' topic
  //this callback function receives cmd_msg object where linear and angular speed are stored
  if(ros_msg_ctrl){
  g_req_linear_vel_x = cmd_msg.linear.x;
  g_req_linear_vel_y = cmd_msg.linear.y;
  g_req_angular_vel_z = -cmd_msg.angular.z;//fanle??
  }
  g_prev_command_time = millis();
}

隨便來個小車實況圖,沒有梳妝,顯得凌亂了些,

ros機器人小車

演示:

安裝麥輪,底盤遙控演示

視頻

安裝普通輪,小車配上雷達,樹莓派安裝ROS 自動導航控制的演示

視頻

總結:

用ROS框架的大腦驅動廉價模塊搭建成的低成本車,賦予Ta靈魂,也基本做到"辭能達意“了,
機器人得有個名字,就叫Ta”晶意智能“車吧,

不滿意小車的表現怎么辦?多添加些其他傳感器?
讓我們深入研究ROS,優化演算法,用智慧補足短板吧,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/272558.html

標籤:其他

上一篇:海思驅動開發之暫存器操作

下一篇:keil RTE HAL庫 STM32CubeMX 串口收發

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more