Um artigo para entender o spin_some, spin e spinOnce do ROS2

Índice

escrito na frente

1. gire e gire Uma vez no ROS

1.1 Análise do mecanismo de callback

1.2 Por que especificar queue_size ao se inscrever em um tópico?

1.3 Dicas para configurar queue_size

1.4 Resumo do uso de spin e spinOnce:

2. spin_some e spin no ROS2

2.1 Pense nas notas oficiais de spin e spin_some

2.2 Uma pequena diferença no spin_some

palavras finais


escrito na frente

ROS2 tem spin_some, spin, e ROS tem spinOnce, spin, qual a diferença e conexão entre eles?

Se você aprendeu ROS, leia apenas a primeira parte.

Se você aprender o ROS2 diretamente, também é recomendável lê-lo para aprofundar sua compreensão.

1. gire e gire Uma vez no ROS

Se você é novo no ROS, provavelmente já leu este tutorial oficial do ROS muito detalhado, que menciona o uso básico de spin e spinOnce. No entanto, estimo que é muito provável que depois de lê-lo, você ainda não entenda a diferença entre os dois e como usá-los.

ROS/Tutorials/WritingPublisherSubscriber(c++) - ROS Wiki http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c++%29 Não se preocupe, vamos extrair o conteúdo relevante e experimentar.

ros::spinOnce()

Chamar ros::spinOnce() aqui não é necessário para este programa simples, porque não estamos recebendo nenhum retorno de chamada. No entanto, se você adicionar uma assinatura a este aplicativo e não tiver ros::spinOnce() aqui, seus retornos de chamada nunca serão chamados. Então, adicione-o para uma boa medida.

O parágrafo acima foi extraído dos comentários do código do nó do editor.

A ideia geral é que, como um programa publicador puro e simples, não há necessidade de usar spinOnce(), porque ele não executa nenhum retorno de chamada. No entanto, se você quiser adicionar funcionalidade de assinatura a este programa sem usar spinOnce(), o retorno de chamada não será gerado.

rosa::girar() 

ros::spin() entra em um loop, chamando callbacks de mensagens o mais rápido possível. Não se preocupe, porém, se não houver nada para fazer, não usará muita CPU. ros::spin() sairá assim que ros::ok() retornar falso, o que significa que ros::shutdown() foi chamado, seja pelo manipulador Ctrl-C padrão, o mestre nos dizendo para desligar ou sendo chamado manualmente.

Esta passagem foi extraída dos comentários do código do nó do assinante.

A ideia geral é que spin() entre em um loop infinito e execute o callback da mensagem o mais rápido possível. No entanto, você não precisa se preocupar com o uso da CPU, porque não consome muitos recursos da CPU quando você não tem nada para fazer. Existem várias maneiras de acionar a saída de spin(), como ros:ok() retornando false (geralmente a partir do resultado da chamada ros::shutdown(), do manipulador ctrl-c ou manualmente).

1.1 Análise do mecanismo de callback

Vamos dar uma olhada na lógica por trás disso.

Primeiro, apenas nós que usam funções de retorno de chamada precisam usar spin ou spinOnce. Geralmente é o nó que precisa assinar o tópico.

No entanto, o assinante da mensagem Assinante especifica apenas a função de retorno de chamada para o tópico. Quando o programa recebe o tópico, ele não executa a função de retorno de chamada imediatamente, mas coloca a função de retorno de chamada em uma fila de função de retorno de chamada. Podemos pensar que toda vez que um tópico for recebido, a função de callback correspondente será colocada na fila, seus nomes de função são os mesmos, mas os parâmetros reais são diferentes.

Então, quando a função de retorno de chamada na fila de funções de retorno de chamada será executada?

Isso requer a ajuda de ros::spin() e ros::spinOnce().

Quando a função spinOnce é chamada, o sistema processará a função de retorno de chamada no início da fila da função de retorno de chamada e sairá após a execução. Então, há um problema nisso. Como o comprimento de qualquer fila de função de retorno de chamada é limitado, se o publicador enviar dados muito rápido, os dados antigos na fila serão substituídos. Quando a frequência da chamada da função spinOnce é muito baixa, haverá perda de dados.

A função spin também pode chamar a função de retorno de chamada na fila de funções de retorno de chamada. Diferente do spinOnce, mesmo que a fila da função callback esteja vazia, ela não sairá, mas aguardará novas tarefas na fila da função callback ciclicamente. Assim que a fila tiver uma função de retorno de chamada, ela será executada imediatamente. Caso contrário, ele continuará bloqueando.

Sim, spin () fará com que o nó entre em um estado de bloqueio, mas não se preocupe, não ocupa muitos recursos da CPU.

1.2 Por que especificar queue_size ao se inscrever em um tópico?

Ao assinar um tópico, o parâmetro queue_size é especificado. É o comprimento da lista de função de retorno de chamada. Ao assinar um tópico, há um buffer de assinatura; ao publicar um tópico, há um buffer de publicação, que limita o comprimento da fila do buffer.

Então, por que existe esse parâmetro?

Para um tópico inscrito, se a frequência de publicação for muito rápida, mas o tempo de processamento na função de retorno de chamada for muito longo, ou porque a frequência de execução do spinOnce for muito baixa, então, durante esta janela de tempo de processamento, alguns tópicos inscritos serão recebidos Conteúdo, esses conteúdos de tópicos acionarão tarefas de retorno de chamada correspondentes, essas tarefas de retorno de chamada estão muito atrasadas para serem processadas e só podem entrar na fila, ou seja, no buffer de assinatura.

Quando a função spin for executada ou spinOnce for executado novamente, o sistema processará as tarefas de retorno de chamada na fila novamente.

Se a área do buffer for grande o suficiente, ocasionalmente a execução da função de retorno de chamada expira e as informações do tópico histórico também podem ser salvas no buffer para garantir que as informações não sejam perdidas. No entanto, se a área do buffer não for grande o suficiente ou o tempo de processamento da função de retorno de chamada continuar a expirar, o estouro do buffer ocorrerá inevitavelmente. Nesse ponto, a tarefa de retorno de chamada mais antiga no cache será perdida e novas tarefas de retorno de chamada serão adicionadas.

Em outras palavras, o buffer é uma fila FIFO primeiro a entrar, primeiro a sair.

1.3 Dicas para configurar queue_size

Normalmente, se você tiver altos requisitos de tempo real e quiser processar as informações da versão mais recente a cada vez, queue_size poderá ser definido como 1, para que cada retorno de chamada processe o tópico mais recente.

Se queue_size for 0, indica que a fila da função callback é infinita. Se você não quiser perder todos os tópicos publicados, pode definir o queue_size um pouco maior, o que consumirá mais recursos de acordo.

A frequência de execução de ros::spinOnce() é 5 Hz e a frequência do tópico inscrito é 10 Hz. Em termos leigos, o tópico é liberado duas vezes durante o intervalo entre duas execuções de spinOnce, então, obviamente, o tamanho da fila do buffer deve be Se for maior que 2, é possível garantir que os dados não serão perdidos.

Claro, isso ainda não pode garantir que as informações não sejam perdidas, apenas podemos dizer que "é possível garantir que os dados não sejam perdidos". Porque a função de retorno de chamada pode demorar muito para ser executada e assim por diante. Esta é outra questão, além do escopo deste artigo.

1.4 Resumo do uso de spin e spinOnce:

1) Não pense que, desde que uma função de callback seja especificada, o sistema irá acioná-la automaticamente. Somente quando o programa é executado ros::spin()ou ros::spinOnce(),a função callback pode realmente ter efeito.

2) Após o programa executar para ros::spin(), ele sempre irá para o buffer de subscrição do tópico para verificar se existe uma função de callback. Em caso afirmativo, processe a função de retorno de chamada; caso contrário, continue verificando e aguarde. Portanto, quando o programa executar ros::spin(), ele continuará esperando pela função callback sem processar outras tarefas. Em outras palavras, o código por trás de ros::spin() não tem chance de ser executado.

3) Quando o programa atingir ros::spinonce(), ele irá para o buffer de assinatura do tópico para verificar se existe uma função de retorno de chamada. Se houver, processe imediatamente uma função de retorno de chamada e saia; caso contrário, saia desta instrução e execute os códigos subsequentes.

4) ros::spinOnce é mais flexível que ros::spin(). Muitas vezes é usado para escrever loops manualmente e pode ser colocado em qualquer lugar do programa. No entanto, a relação entre a frequência de execução de spinOnce e a frequência de publicação do tópico subscrito precisa ser considerado. E spin () é mais rude. De qualquer forma, ele está esperando o tópico ser gerado. Apenas preste atenção para que a função de retorno de chamada não continue a expirar ou verifique se o buffer de assinatura é grande o suficiente.

-------------------------------------------------- ------------------

2. spin_some e spin no ROS2

Não há spinOnce em ros2 e é substituído por spin_some.

Podemos simplesmente entender que a função spin() de ROS1 e ROS2 é usada da mesma forma, e spin_some() é usada da mesma forma que ROS1 ros::spinOnce().

2.1 Pense nas notas oficiais de spin e spin_some

rodar()

Crie um executor de encadeamento único padrão e gire o nó especificado.
Faça o trabalho periodicamente conforme ele estiver disponível para nós. Bloqueando chamada, podendo bloquear indefinidamente.

spin() cria um executor de thread único padrão que atende ao nó especificado. Depois de entrar em vigor, o ciclo é executado. Estado de bloqueio infinito.

spin_some()

Crie um executor de thread único padrão e execute qualquer trabalho imediatamente disponível.
Conclua todo o trabalho em fila disponível sem bloquear.

Esta função pode ser substituída. A implementação padrão é adequada para um modelo de execução de thread único. Adicionar assinaturas, temporizadores, serviços, etc. com callbacks de bloqueio fará com que esta função seja bloqueada (o que pode ter consequências não intencionais).
 

spin() cria um executor de thread único padrão que processa imediatamente tarefas de retorno de chamada válidas e processa todas as tarefas na fila sem bloquear. A julgar pela descrição até aqui, é realmente semelhante à função spinOnce do ROS1.

Então, o segundo parágrafo diz, esta função pode ser substituída! Sua implementação padrão é adequada para um único thread de execução. Ao adicionar tópicos de assinatura, temporizadores, serviços e bloquear funções de retorno de chamada, isso pode fazer com que essa função "originalmente sem bloqueio" também bloqueie e traga consequências imprevisíveis.

Está tudo bem, só sabemos disso.

Tanto quanto eu entendo, em termos leigos, a maior diferença entre spin_some e spinOnce é que uma vez que o primeiro começa a funcionar, ele deve tentar o seu melhor para processar os retornos de chamada válidos no buffer de assinatura; enquanto o último, após o spinOnce começar a funcionar , processa apenas o início da fila. Um retorno de chamada para .

2.2 Uma pequena diferença no spin_some

Existem alguns pequenos detalhes a serem observados ao usar spin_some, tomando C++ como exemplo.

Depois de spin_some, há um nó de parâmetro, que é um ponteiro inteligente do tipo rclcpp::Node. Ao usar spinOnce, esse ponteiro aponta para uma classe que personalizamos, ou seja, uma subclasse de rclcpp::Node. Portanto, traga diretamente no ponteiro this, e rclcpp::spin_some(this) relatará uma incompatibilidade de tipo.

O uso correto é criar um ponteiro inteligente de rclcpp::Node no contexto e apontar para seu objeto de subclasse this, ou seja

rclcpp::Node::SharedPtr node_(this); // 创建基类指针,指向子类对象this
rclcpp::spin_some(node_); // 运行正常

palavras finais

O chamado bloqueio significa que, uma vez que a função entre no papel, ela ficará presa em seu próprio mundo e não poderá sair. Como girar.

O chamado non-blocking é trabalhar quando é hora de trabalhar, e descansar quando é hora de descansar. Faça apenas um trabalho de cada vez, isso é spinOnce; uma vez que você tenha a oportunidade de fazê-lo, você pode fazer mais, isso é spin_some.

Pare aqui.

Espero que ajude você.

Acho que você gosta

Origin blog.csdn.net/slampai/article/details/127992755
Recomendado
Clasificación